fix(db): 修复事务模式下的错误处理与回滚机制

- 在 `queryWithRetry` 和 `execWithRetry` 方法中添加对 `txFailed` 的状态管理,确保在 SQL 错误时正确标记事务失败
- 增加新的测试用例以验证事务模式下的错误处理逻辑,确保在 SQL 错误发生时能够正确回滚
- 优化测试数据库的初始化方法,支持事务测试场景
This commit is contained in:
2026-04-12 00:53:22 +08:00
parent ee3db6cf20
commit 298dbcbcb1
5 changed files with 696 additions and 1292 deletions
-162
View File
@@ -1,9 +1,7 @@
package main
import (
"encoding/json"
"fmt"
"os"
"time"
"code.hoteas.com/golang/hotime"
@@ -11,26 +9,6 @@ import (
. "code.hoteas.com/golang/hotime/common"
)
const debugLogPath = `d:\work\hotimev1.5\.cursor\debug.log`
// debugLog 写入调试日志
func debugLog(hypothesisId, location, message string, data map[string]interface{}) {
logFile, _ := os.OpenFile(debugLogPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if logFile != nil {
logEntry, _ := json.Marshal(map[string]interface{}{
"sessionId": "batch-cache-test",
"runId": "test-run",
"hypothesisId": hypothesisId,
"location": location,
"message": message,
"data": data,
"timestamp": time.Now().UnixMilli(),
})
logFile.Write(append(logEntry, '\n'))
logFile.Close()
}
}
// TestBatchCacheOperations 测试所有批量缓存操作
func TestBatchCacheOperations(app *hotime.Application) {
fmt.Println("\n========== 批量缓存操作测试开始 ==========")
@@ -64,10 +42,6 @@ func TestBatchCacheOperations(app *hotime.Application) {
// testCacheMemoryBatch 测试内存缓存批量操作
func testCacheMemoryBatch(app *hotime.Application) {
// #region agent log
debugLog("E", "batch_cache_test.go:testCacheMemoryBatch:start", "开始测试CacheMemory批量操作", nil)
// #endregion
memCache := &cache.CacheMemory{TimeOut: 3600, DbSet: true, SessionSet: true}
memCache.SetError(&Error{})
@@ -79,22 +53,10 @@ func testCacheMemoryBatch(app *hotime.Application) {
}
memCache.CachesSet(testData)
// #region agent log
debugLog("E", "batch_cache_test.go:testCacheMemoryBatch:afterSet", "CacheMemory.CachesSet完成", map[string]interface{}{"count": len(testData)})
// #endregion
// 测试 CachesGet
keys := []string{"mem_key1", "mem_key2", "mem_key3", "mem_key_not_exist"}
result := memCache.CachesGet(keys)
// #region agent log
debugLog("E", "batch_cache_test.go:testCacheMemoryBatch:afterGet", "CacheMemory.CachesGet完成", map[string]interface{}{
"requested_keys": keys,
"result_count": len(result),
"result_keys": getMapKeys(result),
})
// #endregion
if len(result) != 3 {
fmt.Printf(" [FAIL] CacheMemory.CachesGet: 期望3个结果,实际%d个\n", len(result))
} else {
@@ -105,14 +67,6 @@ func testCacheMemoryBatch(app *hotime.Application) {
memCache.CachesDelete([]string{"mem_key1", "mem_key2"})
result2 := memCache.CachesGet(keys)
// #region agent log
debugLog("E", "batch_cache_test.go:testCacheMemoryBatch:afterDelete", "CacheMemory.CachesDelete完成", map[string]interface{}{
"deleted_keys": []string{"mem_key1", "mem_key2"},
"remaining_count": len(result2),
"remaining_keys": getMapKeys(result2),
})
// #endregion
if len(result2) != 1 || result2["mem_key3"] == nil {
fmt.Printf(" [FAIL] CacheMemory.CachesDelete: 删除后期望1个结果,实际%d个\n", len(result2))
} else {
@@ -122,10 +76,6 @@ func testCacheMemoryBatch(app *hotime.Application) {
// testCacheDbBatch 测试数据库缓存批量操作
func testCacheDbBatch(app *hotime.Application) {
// #region agent log
debugLog("E", "batch_cache_test.go:testCacheDbBatch:start", "开始测试CacheDb批量操作", nil)
// #endregion
// 使用应用的数据库连接
dbCache := &cache.CacheDb{
TimeOut: 3600,
@@ -147,23 +97,10 @@ func testCacheDbBatch(app *hotime.Application) {
}
dbCache.CachesSet(testData)
// #region agent log
debugLog("E", "batch_cache_test.go:testCacheDbBatch:afterSet", "CacheDb.CachesSet完成", map[string]interface{}{"count": len(testData)})
// #endregion
// 测试 CachesGet
keys := []string{"db_batch_key1", "db_batch_key2", "db_batch_key3", "db_not_exist"}
result := dbCache.CachesGet(keys)
// #region agent log
debugLog("E", "batch_cache_test.go:testCacheDbBatch:afterGet", "CacheDb.CachesGet完成", map[string]interface{}{
"requested_keys": keys,
"result_count": len(result),
"result_keys": getMapKeys(result),
"result_values": result,
})
// #endregion
if len(result) != 3 {
fmt.Printf(" [FAIL] CacheDb.CachesGet: 期望3个结果,实际%d个\n", len(result))
} else {
@@ -181,14 +118,6 @@ func testCacheDbBatch(app *hotime.Application) {
dbCache.CachesDelete([]string{"db_batch_key1", "db_batch_key2"})
result2 := dbCache.CachesGet(keys)
// #region agent log
debugLog("E", "batch_cache_test.go:testCacheDbBatch:afterDelete", "CacheDb.CachesDelete完成", map[string]interface{}{
"deleted_keys": []string{"db_batch_key1", "db_batch_key2"},
"remaining_count": len(result2),
"remaining_keys": getMapKeys(result2),
})
// #endregion
if len(result2) != 1 {
fmt.Printf(" [FAIL] CacheDb.CachesDelete: 删除后期望1个结果,实际%d个\n", len(result2))
} else {
@@ -201,10 +130,6 @@ func testCacheDbBatch(app *hotime.Application) {
// testHoTimeCacheBatch 测试 HoTimeCache 三级缓存批量操作
func testHoTimeCacheBatch(app *hotime.Application) {
// #region agent log
debugLog("D", "batch_cache_test.go:testHoTimeCacheBatch:start", "开始测试HoTimeCache三级缓存批量操作", nil)
// #endregion
htCache := app.HoTimeCache
// 清理测试数据
@@ -222,10 +147,6 @@ func testHoTimeCacheBatch(app *hotime.Application) {
}
htCache.SessionsSet(testData)
// #region agent log
debugLog("D", "batch_cache_test.go:testHoTimeCacheBatch:afterSet", "HoTimeCache.SessionsSet完成", map[string]interface{}{"count": len(testData)})
// #endregion
// 测试 SessionsGet
keys := []string{
hotime.HEAD_SESSION_ADD + "ht_batch_key1",
@@ -235,14 +156,6 @@ func testHoTimeCacheBatch(app *hotime.Application) {
}
result := htCache.SessionsGet(keys)
// #region agent log
debugLog("D", "batch_cache_test.go:testHoTimeCacheBatch:afterGet", "HoTimeCache.SessionsGet完成", map[string]interface{}{
"requested_keys": len(keys),
"result_count": len(result),
"result_keys": getMapKeys(result),
})
// #endregion
if len(result) != 3 {
fmt.Printf(" [FAIL] HoTimeCache.SessionsGet: 期望3个结果,实际%d个\n", len(result))
} else {
@@ -256,12 +169,6 @@ func testHoTimeCacheBatch(app *hotime.Application) {
})
result2 := htCache.SessionsGet(keys)
// #region agent log
debugLog("D", "batch_cache_test.go:testHoTimeCacheBatch:afterDelete", "HoTimeCache.SessionsDelete完成", map[string]interface{}{
"remaining_count": len(result2),
})
// #endregion
if len(result2) != 1 {
fmt.Printf(" [FAIL] HoTimeCache.SessionsDelete: 删除后期望1个结果,实际%d个\n", len(result2))
} else {
@@ -274,10 +181,6 @@ func testHoTimeCacheBatch(app *hotime.Application) {
// testSessionInsBatch 测试 SessionIns 批量操作
func testSessionInsBatch(app *hotime.Application) {
// #region agent log
debugLog("B", "batch_cache_test.go:testSessionInsBatch:start", "开始测试SessionIns批量操作", nil)
// #endregion
// 创建一个模拟的 SessionIns
session := &hotime.SessionIns{
SessionId: "test_batch_session_" + ObjToStr(time.Now().UnixNano()),
@@ -292,24 +195,9 @@ func testSessionInsBatch(app *hotime.Application) {
}
session.SessionsSet(testData)
// #region agent log
debugLog("B", "batch_cache_test.go:testSessionInsBatch:afterSet", "SessionIns.SessionsSet完成", map[string]interface{}{
"session_id": session.SessionId,
"count": len(testData),
})
// #endregion
// 测试 SessionsGet
result := session.SessionsGet("field1", "field2", "field3", "not_exist")
// #region agent log
debugLog("B", "batch_cache_test.go:testSessionInsBatch:afterGet", "SessionIns.SessionsGet完成", map[string]interface{}{
"result_count": len(result),
"result_keys": getMapKeys(result),
"result": result,
})
// #endregion
if len(result) != 3 {
fmt.Printf(" [FAIL] SessionIns.SessionsGet: 期望3个结果,实际%d个\n", len(result))
} else {
@@ -334,13 +222,6 @@ func testSessionInsBatch(app *hotime.Application) {
session.SessionsDelete("field1", "field2")
result2 := session.SessionsGet("field1", "field2", "field3")
// #region agent log
debugLog("B", "batch_cache_test.go:testSessionInsBatch:afterDelete", "SessionIns.SessionsDelete完成", map[string]interface{}{
"remaining_count": len(result2),
"remaining_keys": getMapKeys(result2),
})
// #endregion
if len(result2) != 1 {
fmt.Printf(" [FAIL] SessionIns.SessionsDelete: 删除后期望1个结果,实际%d个\n", len(result2))
} else {
@@ -350,10 +231,6 @@ func testSessionInsBatch(app *hotime.Application) {
// testCacheBackfill 测试缓存反哺机制
func testCacheBackfill(app *hotime.Application) {
// #region agent log
debugLog("D", "batch_cache_test.go:testCacheBackfill:start", "开始测试缓存反哺机制", nil)
// #endregion
htCache := app.HoTimeCache
// 直接写入数据库缓存(绕过 memory)模拟只有 db 有数据的情况
@@ -372,24 +249,10 @@ func testCacheBackfill(app *hotime.Application) {
// 直接写入 db
dbCache.Cache(testKey, testValue)
// #region agent log
debugLog("D", "batch_cache_test.go:testCacheBackfill:dbWritten", "数据直接写入DB", map[string]interface{}{
"key": testKey,
"value": testValue,
})
// #endregion
// 通过 HoTimeCache 批量获取,应该触发反哺到 memory
keys := []string{testKey}
result := htCache.CachesGet(keys)
// #region agent log
debugLog("D", "batch_cache_test.go:testCacheBackfill:afterGet", "HoTimeCache.CachesGet完成", map[string]interface{}{
"result_count": len(result),
"has_key": result[testKey] != nil,
})
// #endregion
if len(result) != 1 || result[testKey] == nil {
fmt.Println(" [FAIL] 缓存反哺: 从 DB 读取失败")
} else {
@@ -402,10 +265,6 @@ func testCacheBackfill(app *hotime.Application) {
// testBatchEfficiency 测试批量操作效率
func testBatchEfficiency(app *hotime.Application) {
// #region agent log
debugLog("A", "batch_cache_test.go:testBatchEfficiency:start", "开始测试批量操作效率", nil)
// #endregion
session := &hotime.SessionIns{
SessionId: "efficiency_test_" + ObjToStr(time.Now().UnixNano()),
}
@@ -423,13 +282,6 @@ func testBatchEfficiency(app *hotime.Application) {
batchDuration := time.Since(startTime)
// #region agent log
debugLog("A", "batch_cache_test.go:testBatchEfficiency:batchSet", "批量设置完成", map[string]interface{}{
"count": len(testData),
"duration_ms": batchDuration.Milliseconds(),
})
// #endregion
// 对比单个设置
session2 := &hotime.SessionIns{
SessionId: "efficiency_test_single_" + ObjToStr(time.Now().UnixNano()),
@@ -442,13 +294,6 @@ func testBatchEfficiency(app *hotime.Application) {
}
singleDuration := time.Since(startTime2)
// #region agent log
debugLog("A", "batch_cache_test.go:testBatchEfficiency:singleSet", "单个设置完成", map[string]interface{}{
"count": 10,
"duration_ms": singleDuration.Milliseconds(),
})
// #endregion
fmt.Printf(" 批量设置10个字段耗时: %v\n", batchDuration)
fmt.Printf(" 单个设置10个字段耗时: %v\n", singleDuration)
@@ -467,13 +312,6 @@ func testBatchEfficiency(app *hotime.Application) {
session.SessionsGet(keys...)
batchGetDuration := time.Since(startTime3)
// #region agent log
debugLog("A", "batch_cache_test.go:testBatchEfficiency:batchGet", "批量获取完成", map[string]interface{}{
"count": 10,
"duration_ms": batchGetDuration.Milliseconds(),
})
// #endregion
fmt.Printf(" 批量获取10个字段耗时: %v\n", batchGetDuration)
}