From ca1c8559cf269fd762e78b5c5230e10c1fc9aa13 Mon Sep 17 00:00:00 2001 From: Syngnat Date: Thu, 11 Jun 2026 20:38:50 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(query-editor):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20Oracle=20=E4=BA=8B=E5=8A=A1=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E5=9B=9E=E6=BB=9A=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 分离 Oracle 托管事务与单次查询执行上下文 - 避免查询结束后取消 BeginTx 上下文导致事务提前回滚 - 补充 sql.ErrTxDone 回归测试覆盖 Oracle 提交路径 --- internal/app/app.go | 1 + internal/app/methods_db_multi_test.go | 9 +++++++++ internal/app/methods_db_transaction.go | 19 ++++++++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/internal/app/app.go b/internal/app/app.go index c06865f..f351f71 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -59,6 +59,7 @@ type managedSQLTransaction struct { id string execer db.StatementExecer transactor db.TransactionExecer + cancel context.CancelFunc dbType string commitSQL string rollbackSQL string diff --git a/internal/app/methods_db_multi_test.go b/internal/app/methods_db_multi_test.go index a6ac3b4..e29fda4 100644 --- a/internal/app/methods_db_multi_test.go +++ b/internal/app/methods_db_multi_test.go @@ -2,6 +2,7 @@ package app import ( "context" + "database/sql" "errors" "testing" @@ -227,22 +228,30 @@ type fakeTransactionalDB struct { func (f *fakeTransactionalDB) OpenTransactionExecer(ctx context.Context) (db.TransactionExecer, error) { f.txSession = &fakeTransactionSession{ fakeBatchWriteSession: fakeBatchWriteSession{parent: &f.fakeBatchWriteDB}, + beginCtx: ctx, } return f.txSession, nil } type fakeTransactionSession struct { fakeBatchWriteSession + beginCtx context.Context commitCalls int rollbackCalls int } func (s *fakeTransactionSession) Commit() error { + if s.beginCtx != nil && s.beginCtx.Err() != nil { + return sql.ErrTxDone + } s.commitCalls++ return nil } func (s *fakeTransactionSession) Rollback() error { + if s.beginCtx != nil && s.beginCtx.Err() != nil { + return sql.ErrTxDone + } s.rollbackCalls++ return nil } diff --git a/internal/app/methods_db_transaction.go b/internal/app/methods_db_transaction.go index 4adcd5c..dba4436 100644 --- a/internal/app/methods_db_transaction.go +++ b/internal/app/methods_db_transaction.go @@ -55,11 +55,18 @@ func (a *App) DBQueryMultiTransactional(config connection.ConnectionConfig, dbNa var ( sessionExecer db.StatementExecer transactor db.TransactionExecer + transactionCancel context.CancelFunc startTextTransaction bool ) if provider, ok := dbInst.(db.TransactionExecerProvider); ok { - transactionExecer, err := provider.OpenTransactionExecer(ctx) + transactionContext := context.Background() + if a.ctx != nil { + transactionContext = a.ctx + } + transactionContext, transactionCancel = context.WithCancel(transactionContext) + transactionExecer, err := provider.OpenTransactionExecer(transactionContext) if err != nil { + transactionCancel() logger.Error(err, "DBQueryMultiTransactional 打开驱动事务失败:%s SQL片段=%q", formatConnSummary(runConfig), sqlSnippet(query)) return connection.QueryResult{Success: false, Message: err.Error(), QueryID: queryID} } @@ -95,6 +102,9 @@ func (a *App) DBQueryMultiTransactional(config connection.ConnectionConfig, dbNa if err := sessionExecer.Close(); err != nil { logger.Warnf("DBQueryMultiTransactional 关闭事务会话失败:%v", err) } + if transactionCancel != nil { + transactionCancel() + } } }() @@ -131,6 +141,7 @@ func (a *App) DBQueryMultiTransactional(config connection.ConnectionConfig, dbNa id: transactionID, execer: sessionExecer, transactor: transactor, + cancel: transactionCancel, dbType: runConfig.Type, commitSQL: commitSQL, rollbackSQL: rollbackSQL, @@ -299,6 +310,9 @@ func (a *App) finishManagedSQLTransaction(transactionID string, commit bool) con if !ok || tx == nil || tx.execer == nil { return connection.QueryResult{Success: false, Message: "事务不存在或已结束"} } + if tx.cancel != nil { + defer tx.cancel() + } action := "回滚" sqlText := tx.rollbackSQL @@ -359,6 +373,9 @@ func (a *App) rollbackPendingSQLTransactionsOnShutdown() { } } cancel() + if tx.cancel != nil { + tx.cancel() + } if tx.execer != nil { if err := tx.execer.Close(); err != nil { logger.Warnf("关闭应用时关闭 SQL 编辑器事务会话失败:id=%s dbType=%s err=%v", tx.id, tx.dbType, err)