mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-06-30 15:31:29 +08:00
🐛 fix(sql): 修复 Oracle 托管事务提交回滚失败
This commit is contained in:
@@ -682,6 +682,72 @@ func TestDBQueryMultiTransactionalUsesDriverTransactionForOracle(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDBQueryMultiTransactionalOracleDriverTransactionOutlivesAppContextCancellation(t *testing.T) {
|
||||
originalNewDatabaseFunc := newDatabaseFunc
|
||||
t.Cleanup(func() {
|
||||
newDatabaseFunc = originalNewDatabaseFunc
|
||||
})
|
||||
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
finish func(*App, string) connection.QueryResult
|
||||
wantCommits int
|
||||
wantRollbacks int
|
||||
}{
|
||||
{
|
||||
name: "commit",
|
||||
finish: func(app *App, transactionID string) connection.QueryResult {
|
||||
return app.DBCommitTransaction(transactionID)
|
||||
},
|
||||
wantCommits: 1,
|
||||
},
|
||||
{
|
||||
name: "rollback",
|
||||
finish: func(app *App, transactionID string) connection.QueryResult {
|
||||
return app.DBRollbackTransaction(transactionID)
|
||||
},
|
||||
wantRollbacks: 1,
|
||||
},
|
||||
} {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
stmt := "UPDATE users SET name = 'new' WHERE id = 1"
|
||||
fakeDB := &fakeTransactionalDB{
|
||||
fakeBatchWriteDB: fakeBatchWriteDB{
|
||||
execAffected: map[string]int64{
|
||||
stmt: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
newDatabaseFunc = func(dbType string) (db.Database, error) {
|
||||
return fakeDB, nil
|
||||
}
|
||||
|
||||
appCtx, cancelAppCtx := context.WithCancel(context.Background())
|
||||
app := NewAppWithSecretStore(secretstore.NewUnavailableStore("test"))
|
||||
app.ctx = appCtx
|
||||
config := connection.ConnectionConfig{Type: "oracle", Host: "127.0.0.1", Port: 1521, User: "app"}
|
||||
|
||||
result := app.DBQueryMultiTransactional(config, "ORCLPDB1", stmt, "oracle-tx-context-"+tt.name)
|
||||
if !result.Success {
|
||||
t.Fatalf("expected Oracle transactional query success, got failure: %s", result.Message)
|
||||
}
|
||||
if result.TransactionID == "" || !result.TransactionPending {
|
||||
t.Fatalf("expected pending transaction metadata, got id=%q pending=%v", result.TransactionID, result.TransactionPending)
|
||||
}
|
||||
|
||||
cancelAppCtx()
|
||||
finishResult := tt.finish(app, result.TransactionID)
|
||||
if !finishResult.Success {
|
||||
t.Fatalf("expected Oracle transaction %s success after app context cancellation, got failure: %s", tt.name, finishResult.Message)
|
||||
}
|
||||
if fakeDB.txSession.commitCalls != tt.wantCommits || fakeDB.txSession.rollbackCalls != tt.wantRollbacks {
|
||||
t.Fatalf("expected commits=%d rollbacks=%d, got commits=%d rollbacks=%d",
|
||||
tt.wantCommits, tt.wantRollbacks, fakeDB.txSession.commitCalls, fakeDB.txSession.rollbackCalls)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDBQueryMultiTransactionalRollsBackOracleDriverTransactionOnDMLFailure(t *testing.T) {
|
||||
originalNewDatabaseFunc := newDatabaseFunc
|
||||
t.Cleanup(func() {
|
||||
|
||||
@@ -59,10 +59,10 @@ func (a *App) DBQueryMultiTransactional(config connection.ConnectionConfig, dbNa
|
||||
startTextTransaction bool
|
||||
)
|
||||
if provider, ok := dbInst.(db.TransactionExecerProvider); ok {
|
||||
// database/sql rolls back a BeginTx transaction when its context is cancelled.
|
||||
// SQL editor transactions must outlive the execution RPC and be ended only by
|
||||
// explicit commit, rollback, or shutdown cleanup.
|
||||
transactionContext := context.Background()
|
||||
if a.ctx != nil {
|
||||
transactionContext = a.ctx
|
||||
}
|
||||
transactionContext, transactionCancel = context.WithCancel(transactionContext)
|
||||
transactionExecer, err := provider.OpenTransactionExecer(transactionContext)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user