
TiDB 保存點實操:用 SAVEPOINT 與 ROLLBACK TO SAVEPOINT 只回滾長事務的一半寫入【免費下載鏈接】tidbTiDB is built for agentic workloads that grow unpredictably, with ACID guarantees and native support for transactions, analytics, and vector search. No data silos. No noisy neighbors. No infrastructure ceiling.項目地址: https://gitcode.com/GitHub_Trending/ti/tidb長事務連續執行十幾筆寫入,中途發現某幾步有問題,最直覺的處理是直接ROLLBACK——但這樣會把之前所有寫入一并丟棄,整筆事務推重做。TiDB 支持SAVEPOINT(保存點)與ROLLBACK TO SAVEPOINT(回滾到保存點):在事務內記錄一個檢查點,回滾到該檢查點時只撤銷檢查點之后的數據修改,事務本身繼續可用,之后還能繼續寫入并正常提交。樂觀與悲觀兩種事務模式均支持,可用于替代 gorm 等 ORM 在應用層實現部分回滾的做法。前置確認:哪些會話能使用 SAVEPOINT處于顯式事務中(如BEGIN PESSIMISTIC、BEGIN)。依據:pkg/executor/simple.go 中executeSavepoint對!sessVars.InTxn() sessVars.IsAutocommit()的分支直接返回nil——不在事務中且 autocommit 開啟時,SAVEPOINT是空操作,隨后ROLLBACK TO s1會報[executor:1305]SAVEPOINT s1 does not exist。實例未開啟 binlog。開啟時SAVEPOINT報錯SAVEPOINT is not supported when binlog is enabled(同文件的錯誤變量ErrSavepointNotSupportedWithBinlog);設計文檔 2022-07-22-transaction-savepoint.md 同時注明 TiDB 4.0 之后不建議使用 binlog,該約束只影響少數部署。悲觀事務需開啟 in-place constraint check(約束即時檢查):會話變量tidb_constraint_check_in_place_pessimistic關閉時,SAVEPOINT報錯savepoint is not supported in pessimistic transactions when in-place constraint check is disabled。最小可跑示例:保存點只回滾最后一條插入CREATE TABLE t(id int, a int, UNIQUE INDEX idx(id)); BEGIN PESSIMISTIC; -- 開啟悲觀事務 INSERT INTO t VALUES (1, 1); SAVEPOINT s1; -- 記錄檢查點 s1(事務 MemDB 快照) INSERT INTO t VALUES (2, 2); ROLLBACK TO s1; -- 只回滾 s1 之后的 (2,2),事務不結束 SELECT * FROM t; -- 只剩 (1,1) COMMIT;分步實操:悲觀事務中重復回退到同一保存點以下取自動態測試 executor_txn.test 的TestRollbackToSavepoint場景,預期輸出摘自 executor_txn.result,為示例結果;真實環境中行內容以實際插入的數據為準。第一步:建表、開啟事務、記錄保存點。輸入語句:DROP TABLE IF EXISTS t; CREATE TABLE t(id int, a int, UNIQUE INDEX idx(id)); BEGIN PESSIMISTIC; INSERT INTO t VALUES (1, 1); SAVEPOINT s1; INSERT INTO t VALUES (2, 2);預期輸出:各語句執行成功,無結果集返回。第二步:回退到s1后繼續寫入。原因:ROLLBACK TO s1把事務 MemDB 回退到保存點檢查點,(2,2) 的插入被撤銷,但事務不終止,仍可寫。輸入語句:ROLLBACK TO s1; INSERT INTO t VALUES (2, 2); SELECT * FROM t;預期輸出(示例結果):id a 1 1 2 2第三步:再次回退同一保存點。保存點可以反復使用,第二次回退把新插入的 (2,2) 再撤銷。輸入語句:ROLLBACK TO s1; SELECT * FROM t;預期輸出(示例結果):id a 1 1第四步:提交并驗證最終落盤。輸入語句:COMMIT; SELECT * FROM t;預期輸出(示例結果):id a 1 1第五步:確認保存點之前的修改不受回退影響。回滾只撤銷保存點之后的變更,保存點之前執行的刪除會保留——這是與整事務回滾最本質的行為區別。輸入語句:DELETE FROM t; INSERT INTO t VALUES (1, 1); BEGIN PESSIMISTIC; DELETE FROM t WHERE id 1; SAVEPOINT s1; INSERT INTO t VALUES (1, 2); ROLLBACK TO s1; SELECT * FROM t; COMMIT; SELECT * FROM t;預期輸出(示例結果):兩次SELECT均只有表頭、無數據行——(1,2) 被回滾,保存點之前的刪除生效,提交后仍為空表。邊界與異常:報錯觸發條件及與 MySQL 的差異保存點不存在:ROLLBACK TO/RELEASE SAVEPOINT指向不存在的名稱時均報[executor:1305]SAVEPOINT s1 does not exist(ErrSavepointNotExists)。在事務外空操作過的SAVEPOINT,后續ROLLBACK TO同樣落入該報錯。ROLLBACK TO SAVEPOINT會刪除目標保存點之后的所有保存點。依次創建s1、s2、s3后執行ROLLBACK TO s3,列表只剩s2、s3,再執行ROLLBACK TO s1報 1305;RELEASE SAVEPOINT s2則刪除s2及其后的s3,不提交、不回滾事務,隨后RELEASE SAVEPOINT s3報 1305。保存點名大小寫不敏感:創建s1后執行SAVEPOINT S1,直接替換原條目而非新增(測試斷言列表仍為 3 項且存儲名仍為s1)。上述兩條規則均由 txn_test.go 的TestTxnSavepoint0用例覆蓋。鎖釋放時機與 MySQL 不同:MySQL 在ROLLBACK TO SAVEPOINT時釋放保存點之后持有的鎖;TiDB 悲觀事務不立即釋放,而是在事務提交或整體回滾時統一釋放。回退保存點后,其他會話對相應行的SELECT ... FOR UPDATE可能一直等待到本事務結束。已分配的 AUTO_INCREMENT / SEQUENCE 值不回收,提交后值存在空洞;該行為與 MySQL 一致,屬預期。狀態驗證:判斷保存點是否仍然存在保存點記錄在事務上下文的TxnCtx.Savepoints列表(SavepointRecord結構,見設計文檔),沒有 SQL 語句能直接查詢該列表,只能用間接路徑:執行ROLLBACK TO sp_name:報 1305 說明保存點不存在;不報錯則存在。注意成功即真實回滾,有副作用。執行RELEASE SAVEPOINT sp_name觀察是否報 1305;成功則代表該保存點及其后續保存點被刪除。進程內斷言(單元測試場景)可直接讀取GetSessionVars().TxnCtx.Savepoints字段,TestTxnSavepoint0即靠它在每條語句后斷言列表內容。限制匯總表限制項可觀測現象依據來源binlog 開啟SAVEPOINT is not supported when binlog is enabledpkg/executor/simple.go的ErrSavepointNotSupportedWithBinlog悲觀事務未開啟 in-place checksavepoint is not supported in pessimistic transactions when in-place constraint check is disabledpkg/executor/simple.go的executeSavepoint非事務中且 autocommitSAVEPOINT靜默忽略,后續ROLLBACK TO報 1305pkg/executor/simple.go的executeSavepoint悲觀鎖不隨回退釋放其他會話FOR UPDATE等待到事務結束設計文檔 MySQL Compatibility 一節AUTO_INCREMENT / SEQUENCE 不回收提交后自增值出現空洞設計文檔 ROLLBACK TO SAVEPOINT Implementation 一節保存點列表不可直接查詢只能靠 1305 報錯間接探測pkg/executor/test/txn/txn_test.go的TestTxnSavepoint0【免費下載鏈接】tidbTiDB is built for agentic workloads that grow unpredictably, with ACID guarantees and native support for transactions, analytics, and vector search. No data silos. No noisy neighbors. No infrastructure ceiling.項目地址: https://gitcode.com/GitHub_Trending/ti/tidb創作聲明:本文部分內容由AI輔助生成(AIGC),僅供參考