GORM 跨库事务处理
GORM 原生事务仅支持单库 ACID,跨库事务需借助补偿机制或 Saga 模式实现最终一致性。
单库事务基础
标准事务用法
Go
err := db.Transaction(func(tx *gorm.DB) error {
if err := tx.Create(&user).Error; err != nil {
return err
}
if err := tx.Create(&order).Error; err != nil {
return err
}
return nil
})
跨库事务限制
不支持分布式事务
Go
// 错误示例:两个不同数据库无法使用同一事务
tx1 := db1.Begin()
tx2 := db2.Begin()
tx1.Create(&user) // db1 操作
tx2.Create(&order) // db2 操作
// 无法同时提交/回滚两个事务
注意: GORM 不支持跨库原子事务,需采用补偿机制或外部协调器实现最终一致性。
手动补偿事务
失败回滚 + 补偿操作
Go
func CrossDBOperation(db1, db2 *gorm.DB) error {
tx1 := db1.Begin()
defer func() {
if r := recover(); r != nil {
tx1.Rollback()
}
}()
// db1 操作
if err := tx1.Create(&user).Error; err != nil {
tx1.Rollback()
return err
}
tx2 := db2.Begin()
defer func() {
if r := recover(); r != nil {
tx2.Rollback()
// 补偿:回滚 db1 操作
tx1.Rollback()
}
}()
// db2 操作
if err := tx2.Create(&order).Error; err != nil {
tx2.Rollback()
// 补偿:回滚 db1
tx1.Rollback()
return err
}
// 提交事务(顺序提交,无原子保证)
if err := tx1.Commit().Error; err != nil {
tx2.Rollback()
return err
}
return tx2.Commit().Error
}
Saga 模式实现
步骤定义与补偿
Go
type SagaStep struct {
Action func() error
Compensate func() error
}
type Saga struct {
Steps []SagaStep
}
func (s *Saga) AddStep(action, compensate func() error) {
s.Steps = append(s.Steps, SagaStep{
Action: action,
Compensate: compensate,
})
}
func (s *Saga) Execute() error {
executed := []int{}
// 正向执行
for i, step := range s.Steps {
if err := step.Action(); err != nil {
// 失败则逆向补偿
for j := len(executed) - 1; j >= 0; j-- {
idx := executed[j]
s.Steps[idx].Compensate()
}
return err
}
executed = append(executed, i)
}
return nil
}
// 使用
saga := &Saga{}
saga.AddStep(
func() error { return db1.Create(&user).Error },
func() error { return db1.Delete(&user, user.ID).Error },
)
saga.AddStep(
func() error { return db2.Create(&order).Error },
func() error { return db2.Delete(&order, order.ID).Error },
)
err := saga.Execute()
异步补偿队列
基于消息队列的最终一致性
Go
type PendingCompensation struct {
ID uint `gorm:"primaryKey"`
ServiceName string
Payload string `gorm:"type:text"`
Status string // pending, success, failed
RetryCount int
}
// 记录待补偿操作
func RecordCompensation(db *gorm.DB, service string, payload string) error {
return db.Create(&PendingCompensation{
ServiceName: service,
Payload: payload,
Status: "pending",
}).Error
}
// 定时任务执行补偿
func ProcessCompensations(db *gorm.DB) {
var pendings []PendingCompensation
db.Where("status = ? AND retry_count < ?", "pending", 3).Find(&pendings)
for _, p := range pendings {
err := ExecuteCompensation(p.ServiceName, p.Payload)
if err == nil {
db.Model(&p).Update("status", "success")
} else {
db.Model(&p).Update("retry_count", gorm.Expr("retry_count + ?", 1))
}
}
}
TCC 模式简述
Try-Confirm-Cancel 三阶段
Go
// Try: 预留资源
// Confirm: 确认提交
// Cancel: 取消释放
type TCCService interface {
Try(ctx context.Context) error
Confirm(ctx context.Context) error
Cancel(ctx context.Context) error
}
// 协调器执行
func ExecuteTCC(services []TCCService) error {
// 全部 Try
for _, s := range services {
if err := s.Try(context.Background()); err != nil {
// 失败则全部 Cancel
for _, s := range services {
s.Cancel(context.Background())
}
return err
}
}
// 全部 Confirm
for _, s := range services {
s.Confirm(context.Background())
}
return nil
}
注意: TCC 需业务手动实现 Try/Confirm/Cancel 逻辑,适合对一致性要求高的场景。
要点总结
- GORM 原生事务仅支持单库,跨库需自行实现补偿机制
- 手动补偿方案:失败时逆向回滚已提交操作
- Saga 模式通过步骤定义和补偿函数实现最终一致性
- 异步补偿队列适合对实时性要求不高的场景
- TCC 模式需业务实现三阶段逻辑,一致性更强但复杂度高
存放路径:D:\git2\jwdev\articles\GORM\专家\分库分表与多租户\跨库事务处理.md
📝 发现内容有误?点击此处直接编辑