mongo-driver拥有两种创建事务的方式,但两种方式对事务的开启关闭提交回滚操作有所不同
1.useSession(此处用go-zero举例)
func (m *customUserModel) UseSession(ctx context.Context) error {
db := m.conn.Database()
col := db.Collection("demo")
_, err := col.InsertOne(ctx, bson.M{"_id": "111", "name": "testSession"})
if err != nil {
return err
}
//第一个事务:成功执行
err = db.Client().UseSession(ctx, func(sessionContext mongo.SessionContext) error {
err = sessionContext.StartTransaction()
if err != nil {
fmt.Println(err)
return err
}
//在事务内写一条id为“222”的记录
_, err = col.InsertOne(sessionContext, bson.M{"_id": "111", "name": "testSession"})
if err != nil {
fmt.Println(err)
return err
}
//在事务内写一条id为“333”的记录
_, err = col.InsertOne(sessionContext, bson.M{"_id": "333", "name": "ddd"})
if err != nil {
err := sessionContext.AbortTransaction(sessionContext)
if err != nil {
return err
}
return err
} else {
err := sessionContext.CommitTransaction(sessionContext)
if err != nil {
return err
}
}
return nil
})
if err != nil {
return err
}
err = db.Client().UseSession(ctx, func(sessionContext mongo.SessionContext) error {
err := sessionContext.StartTransaction()
if err != nil {
fmt.Println(err)
return err
}
//在事务内写一条id为“222”的记录
_, err = col.InsertOne(sessionContext, bson.M{"_id": "444", "name": "ddd"})
if err != nil {
fmt.Println(err)
return err
}
//写重复id
_, err = col.InsertOne(sessionContext, bson.M{"_id": "111", "name": "ddd"})
if err != nil {
abortErr := sessionContext.AbortTransaction(sessionContext)
if abortErr != nil {
return abortErr
}
return err
} else {
err := sessionContext.CommitTransaction(sessionContext)
if err != nil {
return err
}
}
return nil
})
if err != nil {
return err
}
return nil
}
2.StartSession
func (m *customUserModel) WithSession(ctx context.Context) error {
db := m.conn.Database()
col := db.Collection("demo")
msgCol := db.Collection("message")
_, err := col.InsertOne(ctx, bson.M{"_id": "111", "user_name": "testSession"})
if err != nil {
return err
}
session, err := db.Client().StartSession()
if err != nil {
return err
}
defer func() {
session.EndSession(ctx)
}()
_, err = session.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
if err != nil {
return nil, err
}
_, err = col.InsertOne(sessCtx, bson.M{"_id": "222", "user_name": "testSession2"})
if err != nil {
return nil, err
}
_, err = col.InsertOne(sessCtx, bson.M{"_id": "333", "user_name": "testSession2"})
if err != nil {
return nil, err
}
//_, err = col.InsertOne(sessCtx, bson.M{"_id": "111", "user_name": "testSession"})
//if err != nil {
// return nil, err
//}
return true, nil
})
if err != nil {
return err
}
return nil
}
可以看出1方式需要手动管理事务的提交回滚,2方式则需要管理事务的开启与关闭。具体可点进UseSession和WithTransaction观察下源码即可
如果执行代码后提示:Transaction numbers are only allowed on a replica set member or mongos
可参考:
MongoDB 运行事务时报“Transaction numbers are only allowed on a replica set member or mongos“错误
参考: