mysql savepoint作用_savepoint原理
保存點
在MySQL中, 保存點SAVEPOINT屬于事務控制處理部分。利用SAVEPOINT可以回滾指定部分事務,從而使事務處理更加靈活和精細。SAVEPOINT相關的SQL語句如下
SAVEPOINT identifier
設置SAVEPOINT。如果重復設置同名savepoint,新的會覆蓋老的.
RELEASE SAVEPOINT identifier
釋放SAVEPOINT。
ROLLBACK [WORK] TO [SAVEPOINT] identifier
回滾到指定的SAVEPOINT。
InnoDB內部實現
保存點跟事務有關,因此我們這里只討論事務引擎InnoDB的savepoint實現。
首先看server層保存點結構:
struct st_savepoint {
struct st_savepoint *prev;
char *name; /* 名字 */
uint length;
Ha_trx_info *ha_list; /* 設置savepoint時已注冊的插件 */
/** State of metadata locks before this savepoint was set. */
MDL_savepoint mdl_savepoint;
};
InnoDB層保存點結構:
保存點結構:
struct trx_named_savept_t{
char* name; /*!< savepoint name */
trx_savept_t savept; /*!< the undo number corresponding to
the savepoint */
ib_int64_t mysql_binlog_cache_pos;
/*!< the MySQL binlog cache position
corresponding to this savepoint, not
defined if the MySQL binlogging is not
enabled */
UT_LIST_NODE_T(trx_named_savept_t)
trx_savepoints; /*!< the list of savepoints of a
transaction */
};
鏈表存儲事務上的所有保存點:
trx_t
{
UT_LIST_BASE_NODE_T(trx_named_savept_t)
trx_savepoints;
…….
}
保存點最重要的信息,事務回滾日志的序號:
struct trx_savept_t{
undo_no_t least_undo_no; /*!< least undo number to undo */
};
SAVEPOINT與UNDO日志
事務回滾通過回滾UNDO日志來實現,同樣,回滾至保存點也是通過應用UNDO日志來實現。
InnoDB事務在每次修改操作時都會記錄UNDO日志,參見函數trx_undo_report_row_operation,每次操作都會記錄UNDO日志序號記為undo_no,每次操作undo_no都會遞增。回滾只需要反向應用UNDO日志即可。 SAVEPOINT與undo_no是一一對應的。
create table t1(c1 int primary key);
begin;
insert into t1 values(1);
savepoint a;
insert into t1 values(2);
savepoint b;
insert into t1 values(3);
rollback to savepoint a;
commit;
SAVEPOINT與BINLOG
InnoDB開啟binlog的情況下,savepoint回滾的那段操作不應記錄binlog. 我們知道,事務執行過程中產生的binlog先寫入cache中,提交時再將cache中的數據寫binlog文件中。 然而,savepoint回滾時,binlog還在cache中,那么被回滾的那段操作的binlog需要從cache中清理掉。
設置savepoint時,記錄binlog在cache中起始位置。
trans_savepoint
->ha_savepoint
->binlog_savepoint_set
->binlog_trans_log_savepos
回滾至savepoint時,從保存的起始位置清理cache
trans_rollback_to_savepoint
->ha_rollback_to_savepoint
->binlog_savepoint_rollback
->binlog_trx_cache_data::restore_savepoint
->binlog_cache_data::truncate
->reinit_io_cache
SAVEPOINT與鎖
回滾保存點以后,此保存點以后的保存點都會釋放,但此保存點以后InnoDB層操作加的鎖不會釋放。這里不釋放鎖,是為了不破壞兩階段鎖協議,減少死鎖的發生。
而對于MDL(metadate lock)鎖,在binlog關閉的情況下可以提前釋放。 而binlog開啟的情況下,需考慮如下情況:
如果操作的僅是InnoDB表且InnoDB層沒有加鎖,則MDL鎖可以釋放,否則,不能釋放。 InnoDB層持有鎖,如果釋放MDL可能出現死鎖。考慮如下情況: trx 1: rollback to savepoint xxx; InnoDB層持有t1的行鎖,釋放t1的MDL trx 2: 操作t1; 持有t1的MDL, 等待t1行鎖 trx 1: 再次操作t1; 等待t1的MDL鎖,從而構成死鎖。
如果操作中有非事務引擎,則不能釋放MDL鎖。 如果是非事務引擎,例如t1為MyiSAM表。 ... begin; insert into t1 values(1); savepoint a; insert into t1 values(2); rollback to savepoint a; commit; ... savepoint和rollback to savepoint之間的sql都會寫入binlog. 如果提前釋放MDL,其他會話drop table t1可以成功,這樣會導致應用binlog時,執行insert into t1 values(2);會找不到表t1。
SAVEPOINT作用域
按官方文檔?中,store function和trigger會重新開啟新的savepoint作用域, store function和trigger完成后老的savepoint作用域重新可用。
A new savepoint level is created when a stored function is invoked or a trigger is activated. The savepoints on previous levels become unavailable and thus do not conflict with savepoints on the new level. When the function or trigger terminates, any savepoints it created are released and the previous savepoint level is restored.
delimiter //
drop procedure if exists p1//
create procedure p1()
begin
release savepoint a;
end//
delimiter ;
begin;
savepoint a;
call p1();
rollback to savepoint a;
ERROR 1305 (42000): SAVEPOINT a does not exist
從結果來看與官方文檔描述并不一致。
實際從代碼中上看,stored function和trigger并沒有開啟獨立的事務,而是與調用著共用同一事務。savepoint都在同一事務的鏈表中,因此store function和trigger中的savepoint作用域和調用者相同。
官方對savepoint的實現并不徹底。
匿名SAVEPOINT
實際上,InnoDB事務中每個語句執行前都會記錄一個匿名savepoint;如果當前語句執行失敗,不會回滾整個事務,而是利用這個匿名savepoint回滾失敗的語句。
struct trx_t{
trx_savept_t last_sql_stat_start; //匿名savepoint
......
總結
以上是生活随笔為你收集整理的mysql savepoint作用_savepoint原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NVIDIA RTX 2050、MX57
- 下一篇: 19岁的网红餐厅新元素突然破产:曾经几亿