refactor(db): 增强测试事务和缓存管理

- 在 HoTimeDB 中新增 testMu 互斥锁,确保 testTx 的串行访问,解决并发冲突问题
- 在 BeginTestTx 中初始化 testMu,确保测试事务的安全性
- 在 HoTimeCache 中新增 DisableDbCache 方法,测试模式下禁用 DB 和 Redis 缓存,避免锁等待超时
- 更新 Select 方法,确保在 testTx 激活时跳过缓存逻辑,提升测试稳定性
- 优化 Swagger 生成逻辑,支持模块化输出和导航页生成
- 移除冗余的调试日志代码,提升代码整洁性
This commit is contained in:
2026-03-14 13:06:32 +08:00
parent 93596ad0dc
commit 3feaa69fe4
9 changed files with 254 additions and 205 deletions
+2 -5
View File
@@ -135,23 +135,20 @@ func (that *HoTimeDB) Select(table string, qu ...interface{}) []Map {
qs = append(qs, resWhere...)
md5 := that.md5(query, qs...)
if that.HoTimeCache != nil && table != "cached" {
// 如果缓存有则从缓存取
if that.testTx == nil && that.HoTimeCache != nil && table != "cached" {
cacheData := that.HoTimeCache.Db(table + ":" + md5)
if cacheData != nil && cacheData.Data != nil {
return cacheData.ToMapArray()
}
}
// 无缓存则数据库取
res := that.Query(query, qs...)
if res == nil {
res = []Map{}
}
// 缓存
if that.HoTimeCache != nil && table != "cached" {
if that.testTx == nil && that.HoTimeCache != nil && table != "cached" {
_ = that.HoTimeCache.Db(table+":"+md5, res)
}
+3 -1
View File
@@ -32,7 +32,8 @@ type HoTimeDB struct {
mu sync.RWMutex
limitMu sync.Mutex
Dialect Dialect // 数据库方言适配器
testTx *sql.Tx // 测试事务:设置后所有操作都在此事务内,测试结束回滚
testTx *sql.Tx // 测试事务:设置后所有操作都在此事务内,测试结束回滚
testMu *sync.Mutex // 保护 testTx 单连接不被并发访问
}
// SetConnect 设置数据库配置连接
@@ -154,6 +155,7 @@ func (that *HoTimeDB) BeginTestTx() error {
return err
}
that.testTx = tx
that.testMu = &sync.Mutex{}
return nil
}
+15 -2
View File
@@ -62,7 +62,16 @@ func (that *HoTimeDB) queryWithRetry(query string, retried bool, args ...interfa
processedArgs := that.processArgs(args)
if that.testTx != nil {
if that.testMu != nil { that.testMu.Lock() }
resl, err = that.testTx.Query(query, processedArgs...)
that.LastErr.SetError(err)
if err != nil {
if that.testMu != nil { that.testMu.Unlock() }
return nil
}
result := that.Row(resl)
if that.testMu != nil { that.testMu.Unlock() }
return result
} else if that.Tx != nil {
resl, err = that.Tx.Query(query, processedArgs...)
} else {
@@ -71,7 +80,6 @@ func (that *HoTimeDB) queryWithRetry(query string, retried bool, args ...interfa
that.LastErr.SetError(err)
if err != nil {
// 如果还没重试过,尝试 Ping 后重试一次
if !retried {
if pingErr := db.Ping(); pingErr == nil {
return that.queryWithRetry(query, true, args...)
@@ -120,7 +128,9 @@ func (that *HoTimeDB) execWithRetry(query string, retried bool, args ...interfac
processedArgs := that.processArgs(args)
if that.testTx != nil {
if that.testMu != nil { that.testMu.Lock() }
resl, e = that.testTx.Exec(query, processedArgs...)
if that.testMu != nil { that.testMu.Unlock() }
} else if that.Tx != nil {
resl, e = that.Tx.Exec(query, processedArgs...)
} else {
@@ -128,8 +138,11 @@ func (that *HoTimeDB) execWithRetry(query string, retried bool, args ...interfac
}
that.LastErr.SetError(e)
// 判断是否连接断开了,如果还没重试过,尝试重试一次
if e != nil {
// testTx 模式下不走连接池重试,避免 busy buffer
if that.testTx != nil {
return resl, that.LastErr
}
if !retried {
if pingErr := that.DB.Ping(); pingErr == nil {
return that.execWithRetry(query, true, args...)
+7
View File
@@ -32,17 +32,24 @@ func (that *HoTimeDB) Action(action func(db HoTimeDB) (isSuccess bool)) (isSucce
mu: sync.RWMutex{},
limitMu: sync.Mutex{},
testTx: that.testTx,
testMu: that.testMu,
}
if that.testTx != nil {
spName := fmt.Sprintf("sp_%d", atomic.AddUint64(&savepointCounter, 1))
if that.testMu != nil { that.testMu.Lock() }
_, _ = that.testTx.Exec("SAVEPOINT " + spName)
if that.testMu != nil { that.testMu.Unlock() }
db.Tx = that.testTx
isSuccess = action(db)
if !isSuccess {
if that.testMu != nil { that.testMu.Lock() }
_, _ = that.testTx.Exec("ROLLBACK TO SAVEPOINT " + spName)
if that.testMu != nil { that.testMu.Unlock() }
} else {
if that.testMu != nil { that.testMu.Lock() }
_, _ = that.testTx.Exec("RELEASE SAVEPOINT " + spName)
if that.testMu != nil { that.testMu.Unlock() }
}
return isSuccess
}