2026-01-22 04:59:53 +08:00
|
|
|
package db
|
|
|
|
|
|
|
|
|
|
import (
|
2026-03-14 10:19:57 +08:00
|
|
|
"fmt"
|
2026-01-22 04:59:53 +08:00
|
|
|
"sync"
|
2026-03-14 10:19:57 +08:00
|
|
|
"sync/atomic"
|
2026-01-22 04:59:53 +08:00
|
|
|
)
|
|
|
|
|
|
2026-03-14 10:19:57 +08:00
|
|
|
var savepointCounter uint64
|
|
|
|
|
|
2026-01-22 04:59:53 +08:00
|
|
|
// Action 事务操作
|
|
|
|
|
// 如果 action 返回 true 则提交事务;返回 false 则回滚
|
2026-03-14 10:19:57 +08:00
|
|
|
// 测试模式下(testTx != nil),使用 SAVEPOINT 代替真事务,确保嵌套事务不会绕过外层测试事务
|
2026-01-22 04:59:53 +08:00
|
|
|
func (that *HoTimeDB) Action(action func(db HoTimeDB) (isSuccess bool)) (isSuccess bool) {
|
2026-04-04 01:57:10 +08:00
|
|
|
that.testLogBufMu.Lock()
|
|
|
|
|
logBuf := that.testLogBuf
|
|
|
|
|
that.testLogBufMu.Unlock()
|
2026-01-22 04:59:53 +08:00
|
|
|
db := HoTimeDB{
|
|
|
|
|
DB: that.DB,
|
|
|
|
|
ContextBase: that.ContextBase,
|
|
|
|
|
DBName: that.DBName,
|
|
|
|
|
HoTimeCache: that.HoTimeCache,
|
|
|
|
|
Log: that.Log,
|
|
|
|
|
Type: that.Type,
|
|
|
|
|
Prefix: that.Prefix,
|
|
|
|
|
ConnectFunc: that.ConnectFunc,
|
|
|
|
|
limit: that.limit,
|
|
|
|
|
Tx: that.Tx,
|
|
|
|
|
SlaveDB: that.SlaveDB,
|
|
|
|
|
Dialect: that.Dialect,
|
|
|
|
|
limitMu: sync.Mutex{},
|
2026-03-14 10:19:57 +08:00
|
|
|
testTx: that.testTx,
|
2026-03-14 13:06:32 +08:00
|
|
|
testMu: that.testMu,
|
2026-04-04 01:57:10 +08:00
|
|
|
testLogBuf: logBuf,
|
2026-03-14 10:19:57 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-11 21:53:28 +08:00
|
|
|
txFailed := false
|
|
|
|
|
db.txFailed = &txFailed
|
|
|
|
|
|
2026-03-14 10:19:57 +08:00
|
|
|
if that.testTx != nil {
|
|
|
|
|
spName := fmt.Sprintf("sp_%d", atomic.AddUint64(&savepointCounter, 1))
|
2026-04-11 21:53:28 +08:00
|
|
|
if that.testMu != nil {
|
|
|
|
|
that.testMu.Lock()
|
|
|
|
|
}
|
2026-03-14 10:19:57 +08:00
|
|
|
_, _ = that.testTx.Exec("SAVEPOINT " + spName)
|
2026-04-11 21:53:28 +08:00
|
|
|
if that.testMu != nil {
|
|
|
|
|
that.testMu.Unlock()
|
|
|
|
|
}
|
2026-03-14 10:19:57 +08:00
|
|
|
db.Tx = that.testTx
|
|
|
|
|
isSuccess = action(db)
|
2026-04-11 21:53:28 +08:00
|
|
|
if txFailed || !isSuccess {
|
|
|
|
|
if that.testMu != nil {
|
|
|
|
|
that.testMu.Lock()
|
|
|
|
|
}
|
2026-03-14 10:19:57 +08:00
|
|
|
_, _ = that.testTx.Exec("ROLLBACK TO SAVEPOINT " + spName)
|
2026-04-11 21:53:28 +08:00
|
|
|
if that.testMu != nil {
|
|
|
|
|
that.testMu.Unlock()
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if that.testMu != nil {
|
|
|
|
|
that.testMu.Lock()
|
|
|
|
|
}
|
|
|
|
|
_, _ = that.testTx.Exec("RELEASE SAVEPOINT " + spName)
|
|
|
|
|
if that.testMu != nil {
|
|
|
|
|
that.testMu.Unlock()
|
2026-03-14 10:19:57 +08:00
|
|
|
}
|
|
|
|
|
return isSuccess
|
2026-01-22 04:59:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tx, err := db.Begin()
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
2026-04-13 00:38:50 +08:00
|
|
|
dbErr := &DBError{}
|
|
|
|
|
dbErr.SetError(err)
|
|
|
|
|
that.lastError.Store(dbErr)
|
2026-01-22 04:59:53 +08:00
|
|
|
return isSuccess
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
db.Tx = tx
|
|
|
|
|
|
|
|
|
|
isSuccess = action(db)
|
|
|
|
|
|
2026-04-11 21:53:28 +08:00
|
|
|
if txFailed {
|
|
|
|
|
_ = db.Tx.Rollback()
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-22 04:59:53 +08:00
|
|
|
if !isSuccess {
|
|
|
|
|
err = db.Tx.Rollback()
|
|
|
|
|
if err != nil {
|
2026-04-13 00:38:50 +08:00
|
|
|
dbErr := &DBError{}
|
|
|
|
|
dbErr.SetError(err)
|
|
|
|
|
that.lastError.Store(dbErr)
|
2026-01-22 04:59:53 +08:00
|
|
|
return isSuccess
|
|
|
|
|
}
|
|
|
|
|
return isSuccess
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = db.Tx.Commit()
|
|
|
|
|
if err != nil {
|
2026-04-13 00:38:50 +08:00
|
|
|
dbErr := &DBError{}
|
|
|
|
|
dbErr.SetError(err)
|
|
|
|
|
that.lastError.Store(dbErr)
|
2026-01-22 04:59:53 +08:00
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
}
|