273 lines
9.8 KiB
Markdown
273 lines
9.8 KiB
Markdown
|
|
# 事务管理方案说明
|
|||
|
|
|
|||
|
|
## 概述
|
|||
|
|
|
|||
|
|
本方案通过Context传递GORM事务对象,实现简单直接的事务管理,避免了复杂的Saga分布式事务框架。所有事务相关功能统一在 `shared/database` 包中管理。
|
|||
|
|
|
|||
|
|
## 架构设计
|
|||
|
|
|
|||
|
|
### 分层职责
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────────────────────────────┐
|
|||
|
|
│ 应用服务层 (Application) │
|
|||
|
|
│ ┌─────────────────────────────────────────────────────────┐ │
|
|||
|
|
│ │ 使用 TransactionManager.ExecuteInTx() 进行事务管理 │ │
|
|||
|
|
│ └─────────────────────────────────────────────────────────┘ │
|
|||
|
|
└─────────────────────────────────────────────────────────────┘
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────────────────────────────────┐
|
|||
|
|
│ 共享层 (Shared) │
|
|||
|
|
│ ┌─────────────────────────────────────────────────────────┐ │
|
|||
|
|
│ │ shared/database/transaction.go │ │
|
|||
|
|
│ │ - TransactionManager (事务管理器) │ │
|
|||
|
|
│ │ - Context传递机制 │ │
|
|||
|
|
│ │ - 事务选项和统计 │ │
|
|||
|
|
│ └─────────────────────────────────────────────────────────┘ │
|
|||
|
|
└─────────────────────────────────────────────────────────────┘
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────────────────────────────────┐
|
|||
|
|
│ 基础设施层 (Infrastructure) │
|
|||
|
|
│ ┌─────────────────────────────────────────────────────────┐ │
|
|||
|
|
│ │ infrastructure/database/database.go │ │
|
|||
|
|
│ │ - 数据库连接管理 │ │
|
|||
|
|
│ │ - 连接池配置 │ │
|
|||
|
|
│ │ - 基础数据库操作 │ │
|
|||
|
|
│ └─────────────────────────────────────────────────────────┘ │
|
|||
|
|
└─────────────────────────────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 核心组件
|
|||
|
|
|
|||
|
|
### 1. 事务管理器 (TransactionManager)
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// 位置: internal/shared/database/transaction.go
|
|||
|
|
type TransactionManager struct {
|
|||
|
|
db *gorm.DB
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 主要方法:
|
|||
|
|
// - ExecuteInTx() - 推荐使用的事务执行方法
|
|||
|
|
// - ExecuteInTxWithTimeout() - 带超时的事务执行
|
|||
|
|
// - ExecuteInTxWithOptions() - 带选项的事务执行
|
|||
|
|
// - BeginTx() - 手动开始事务
|
|||
|
|
// - NewTxWrapper() - 创建事务包装器
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. Context工具函数
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// WithTx 将事务对象存储到context中
|
|||
|
|
func WithTx(ctx context.Context, tx *gorm.DB) context.Context
|
|||
|
|
|
|||
|
|
// GetTx 从context中获取事务对象
|
|||
|
|
func GetTx(ctx context.Context) (*gorm.DB, bool)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 仓储层支持
|
|||
|
|
|
|||
|
|
所有GORM仓储实现都添加了`getDB`方法:
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// getDB 获取数据库连接,优先使用事务
|
|||
|
|
func (r *GormEnterpriseInfoSubmitRecordRepository) getDB(ctx context.Context) *gorm.DB {
|
|||
|
|
if tx, ok := database.GetTx(ctx); ok {
|
|||
|
|
return tx
|
|||
|
|
}
|
|||
|
|
return r.db
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 使用方式
|
|||
|
|
|
|||
|
|
### 1. 基础事务执行(推荐)
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// 应用服务层
|
|||
|
|
func (s *CertificationApplicationServiceImpl) SubmitEnterpriseInfo(ctx context.Context, cmd *commands.SubmitEnterpriseInfoCommand) (*responses.EnterpriseInfoResponse, error) {
|
|||
|
|
// 1. 验证企业信息
|
|||
|
|
exists, err := s.enterpriseService.CheckUnifiedSocialCodeExists(ctx, cmd.UnifiedSocialCode, "")
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, fmt.Errorf("检查企业信息失败: %w", err)
|
|||
|
|
}
|
|||
|
|
if exists {
|
|||
|
|
return nil, fmt.Errorf("统一社会信用代码已存在")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2. 获取或创建认证申请
|
|||
|
|
certification, err := s.certManagementService.GetCertificationByUserID(ctx, cmd.UserID)
|
|||
|
|
if err != nil {
|
|||
|
|
// 处理错误...
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3. 使用事务执行状态转换和创建记录
|
|||
|
|
var recordID string
|
|||
|
|
var createdRecord entities.EnterpriseInfoSubmitRecord
|
|||
|
|
|
|||
|
|
err = s.txManager.ExecuteInTx(ctx, func(txCtx context.Context) error {
|
|||
|
|
// 步骤1:创建企业信息提交记录
|
|||
|
|
record := entities.NewEnterpriseInfoSubmitRecord(
|
|||
|
|
certification.ID,
|
|||
|
|
cmd.UserID,
|
|||
|
|
cmd.CompanyName,
|
|||
|
|
cmd.UnifiedSocialCode,
|
|||
|
|
cmd.LegalPersonName,
|
|||
|
|
cmd.LegalPersonID,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
var err error
|
|||
|
|
createdRecord, err = s.enterpriseRecordRepo.Create(txCtx, *record)
|
|||
|
|
if err != nil {
|
|||
|
|
return fmt.Errorf("创建企业信息提交记录失败: %w", err)
|
|||
|
|
}
|
|||
|
|
recordID = createdRecord.ID
|
|||
|
|
|
|||
|
|
// 步骤2:状态转换
|
|||
|
|
err = s.certWorkflowService.SubmitEnterpriseInfo(txCtx, certification.ID)
|
|||
|
|
if err != nil {
|
|||
|
|
return fmt.Errorf("状态转换失败: %w", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
if err != nil {
|
|||
|
|
s.logger.Error("事务执行失败", zap.Error(err))
|
|||
|
|
return nil, fmt.Errorf("企业信息提交失败: %w", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 返回成功响应...
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 带超时的事务执行
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// 设置30秒超时
|
|||
|
|
err = s.txManager.ExecuteInTxWithTimeout(ctx, 30*time.Second, func(txCtx context.Context) error {
|
|||
|
|
// 事务操作...
|
|||
|
|
return nil
|
|||
|
|
})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 带选项的事务执行
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
options := &database.TransactionOptions{
|
|||
|
|
Timeout: 30 * time.Second,
|
|||
|
|
ReadOnly: false,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
err = s.txManager.ExecuteInTxWithOptions(ctx, options, func(txCtx context.Context) error {
|
|||
|
|
// 事务操作...
|
|||
|
|
return nil
|
|||
|
|
})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4. 手动事务管理(高级用法)
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// 手动管理事务
|
|||
|
|
txWrapper := s.txManager.NewTxWrapper()
|
|||
|
|
defer func() {
|
|||
|
|
if err != nil {
|
|||
|
|
txWrapper.Rollback()
|
|||
|
|
}
|
|||
|
|
}()
|
|||
|
|
|
|||
|
|
// 使用事务
|
|||
|
|
txCtx := database.WithTx(ctx, txWrapper.GetDB())
|
|||
|
|
err = s.enterpriseRecordRepo.Create(txCtx, record)
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 提交事务
|
|||
|
|
err = txWrapper.Commit()
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5. 仓储层自动事务支持
|
|||
|
|
|
|||
|
|
仓储层会自动从context中获取事务对象:
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// Create 创建企业信息提交记录
|
|||
|
|
func (r *GormEnterpriseInfoSubmitRecordRepository) Create(ctx context.Context, record entities.EnterpriseInfoSubmitRecord) (entities.EnterpriseInfoSubmitRecord, error) {
|
|||
|
|
r.logger.Info("创建企业信息提交记录", zap.String("certification_id", record.CertificationID))
|
|||
|
|
err := r.getDB(ctx).WithContext(ctx).Create(&record).Error
|
|||
|
|
return record, err
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 优势
|
|||
|
|
|
|||
|
|
1. **统一管理**: 所有事务相关功能集中在 `shared/database` 包中
|
|||
|
|
2. **简单直接**: 不需要复杂的状态管理和补偿逻辑
|
|||
|
|
3. **自动回滚**: 任何步骤失败都会自动回滚整个事务
|
|||
|
|
4. **类型安全**: 通过Context传递,类型安全
|
|||
|
|
5. **易于理解**: 代码逻辑清晰,易于维护
|
|||
|
|
6. **性能好**: 避免了分布式事务的开销
|
|||
|
|
7. **灵活配置**: 支持超时、只读等选项
|
|||
|
|
8. **向后兼容**: 保留旧接口,平滑迁移
|
|||
|
|
|
|||
|
|
## 适用场景
|
|||
|
|
|
|||
|
|
- 单数据库事务
|
|||
|
|
- 简单的业务流程编排
|
|||
|
|
- 需要原子性操作的场景
|
|||
|
|
- 对性能要求较高的场景
|
|||
|
|
- 需要事务超时控制的场景
|
|||
|
|
|
|||
|
|
## 注意事项
|
|||
|
|
|
|||
|
|
1. 只适用于单数据库事务
|
|||
|
|
2. 不支持跨服务的分布式事务
|
|||
|
|
3. 需要确保所有仓储都支持事务传递
|
|||
|
|
4. 事务超时需要合理设置
|
|||
|
|
5. 避免在事务中执行长时间操作
|
|||
|
|
|
|||
|
|
## 与Saga的对比
|
|||
|
|
|
|||
|
|
| 特性 | 事务管理方案 | Saga方案 |
|
|||
|
|
|------|-------------|----------|
|
|||
|
|
| 复杂度 | 简单 | 复杂 |
|
|||
|
|
| 性能 | 高 | 中等 |
|
|||
|
|
| 适用场景 | 单数据库 | 分布式 |
|
|||
|
|
| 维护成本 | 低 | 高 |
|
|||
|
|
| 错误处理 | 自动回滚 | 需要补偿逻辑 |
|
|||
|
|
| 超时控制 | 内置支持 | 需要额外实现 |
|
|||
|
|
| 统计监控 | 预留接口 | 复杂 |
|
|||
|
|
|
|||
|
|
## 迁移指南
|
|||
|
|
|
|||
|
|
### 从旧的事务管理迁移
|
|||
|
|
|
|||
|
|
1. **替换基础设施层的事务调用**:
|
|||
|
|
```go
|
|||
|
|
// 旧方式
|
|||
|
|
err := db.WithTx(func(tx *gorm.DB) error {
|
|||
|
|
// 事务操作
|
|||
|
|
return nil
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// 新方式
|
|||
|
|
txManager := database.NewTransactionManager(db)
|
|||
|
|
err := txManager.ExecuteInTx(ctx, func(txCtx context.Context) error {
|
|||
|
|
// 事务操作
|
|||
|
|
return nil
|
|||
|
|
})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. **更新仓储层**: 确保所有仓储都使用 `getDB(ctx)` 方法
|
|||
|
|
|
|||
|
|
3. **更新应用服务**: 使用 `TransactionManager` 替代直接的事务调用
|
|||
|
|
|
|||
|
|
## 未来扩展
|
|||
|
|
|
|||
|
|
1. **事务统计**: 实现事务执行统计和监控
|
|||
|
|
2. **分布式事务**: 在需要时扩展为分布式事务支持
|
|||
|
|
3. **事务链路追踪**: 集成链路追踪系统
|
|||
|
|
4. **事务重试**: 添加自动重试机制
|