# mongo update 鎖測試 https://hub.docker.com/r/bitnami/mongodb-sharded/ ``` func UseSessionNoSleep(client *mongo.Client, userID int) { ctx := context.Background() collection := client.Database("yolo").Collection("user") session, err := client.StartSession() if err != nil { log.Fatal(err) } result, err := session.WithTransaction(ctx, func(sCtx mongo.SessionContext) (interface{}, error) { objID, _ := primitive.ObjectIDFromHex("61ef6bd8a6c0946e9484b3a9") result, err := collection.UpdateOne(sCtx, bson.D{{"_id", objID}, {"age", bson.D{{"$gt", 0}}}}, bson.D{{"$inc", bson.D{{"age", -1}}}}) if err != nil { return nil, err } return result, nil }) if err != nil { fmt.Printf("userID:%d err:%s\n", userID, err) } fmt.Printf("userID:%d result:%v\n", userID, result) } func UseSessionHasSleep(client *mongo.Client, userID int) { ctx := context.Background() collection := client.Database("yolo").Collection("user") session, err := client.StartSession() if err != nil { log.Fatal(err) } result, err := session.WithTransaction(ctx, func(sCtx mongo.SessionContext) (interface{}, error) { objID, _ := primitive.ObjectIDFromHex("61ef6bd8a6c0946e9484b3a9") result, err := collection.UpdateOne(sCtx, bson.D{{"_id", objID}, {"age", bson.D{{"$gt", 0}}}}, bson.D{{"$inc", bson.D{{"age", -1}}}}) if err != nil { rand.Seed(time.Now().UnixNano()) d := time.Second * time.Duration(rand.Intn(20)) time.Sleep(d) return nil, err } return result, nil }) if err != nil { fmt.Printf("userID:%d err:%s\n", userID, err) } fmt.Printf("userID:%d result:%v\n", userID, result) } func UpdateWithoutSession(client *mongo.Client, userID int) { ctx := context.Background() collection := client.Database("yolo").Collection("user") objID, _ := primitive.ObjectIDFromHex("61ef6bd8a6c0946e9484b3a9") result, err := collection.UpdateOne(ctx, bson.D{{"_id", objID}, {"age", bson.D{{"$gt", 0}}}}, bson.D{{"$inc", bson.D{{"age", -1}}}}) if err != nil { fmt.Printf("userID:%d err:%s\n", userID, err) } fmt.Printf("userID:%d result:%v\n", userID, result) } func main() { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() client, err := mongo.Connect( ctx, options.Client().ApplyURI("mongodb://localhost:27017"), options.Client().SetAuth(options.Credential{ Username: "root", Password: "password123", }), ) if err != nil { log.Fatal(err) } defer func() { _ = client.Disconnect(ctx) }() var wg sync.WaitGroup maxNum := 1000 wg.Add(maxNum) now := time.Now() // 初始庫存為 100, 1000 人同時搶 for i := 0; i < maxNum; i++ { go func(userID int) { defer wg.Done() // 沒有辦法執行完 //UseSessionNoSleep(client, userID) // 約 25 秒 //UseSessionHasSleep(client, userID) // 約 2 秒 UpdateWithoutSession(client, userID) }(i) } wg.Wait() fmt.Printf("operation finished cost %s\n", time.Since(now).String()) fmt.Println() } ```