H2 Database 事务 Rollback 流程实现原理
使用
1 2 3 4 5 6 7
| Connection conn = getConnection();
conn.setAutoCommit(false);
executeWithLog(conn, "insert into Test(id, name) values(1, 'name1'), (2, 'name2')");
conn.rollback();
|
功能
模块
类
总体流程
当执行事务回滚时,会获取当前事务所有的 undoLogId,然后从后向前遍历每一个 undoLogId。
对于每一个 undoLogId,先遍历 undoLog btree 找到存储的 Record。Record 信息里包含了当前 undoLogId 操作的数据行信息。
然后根据 Record 信息找到对应记录的 primary key btree,根据主键 id 找到对应行记录进行回滚操作。
当记录回滚完之后,再回滚 undoLog btree 上的 undoLog 信息。
1 2 3 4 5 6
| 获取 transaction id 和 当前 undo log id. 从当前 undo log id 一直遍历到 0(事务刚开启时 undoLogId=0),回滚当前事务的所有操作. 根据 undo log key 定位到 undo log btree 上的指定位置,获取存储的 record record 包含当前 undo log 操作的 mvMap(比如 Primary key) 的 mapId, key(比如主键 id), oldValue 再根据 record 打开 primary key mvMap,定位到 row key, 然后决定从 mvMap 上移除当前值 再移除 undo log mvMap 上的当前 undo log key 对应的值
|
代码流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| org.h2.jdbc.JdbcStatement#executeInternal org.h2.jdbc.JdbcConnection#prepareCommand 解析 rollback 语句 org.h2.command.Command#executeUpdate org.h2.engine.SessionLocal#setSavepoint 设置savepoint,返回新的logId org.h2.command.dml.TransactionCommand#update org.h2.engine.SessionLocal#rollback org.h2.engine.SessionLocal#hasTransaction 判断在事务中 org.h2.engine.SessionLocal#rollbackTo 执行回滚 org.h2.mvstore.tx.Transaction#rollback 回滚 org.h2.mvstore.tx.Transaction#setStatus 1.尝试设置事务状态为 ROLLED_BACK,并获取之前的事务状态 获取事务当前的 state & logId org.h2.mvstore.tx.Transaction#getLogId 获取当前 undo log id org.h2.mvstore.tx.Transaction#getStatus 获取事务当前状态 2.判断当前状态允许变更为目标状态,然后变更为目标状态 org.h2.mvstore.tx.Transaction#composeState 新状态(transaction status + undo log id) 3.原子变更 statusAndLogId 获取当前 status 和 logId org.h2.mvstore.tx.TransactionStore#rollbackTo 回滚 org.h2.mvstore.tx.RollbackDecisionMaker#init0 创建 rollback decision maker 3.遍历从 maxLogId 到 toLogId,依次进行回滚操作 org.h2.mvstore.tx.TransactionStore#getOperationId 3.1.计算 undo log key (transaction id + log id) org.h2.mvstore.MVMap#operate 3.2.根据 undo log key 操作 undo log mvMap, 执行回滚操作 org.h2.mvstore.MVMap#flushAndGetRoot 获取 undo log mvMap 根节点 org.h2.mvstore.CursorPos#traverseDown 找到 undoLog 位置 org.h2.mvstore.MVMap.DecisionMaker#decide 内部会先回滚该 undoLog 对应的 mvMap上 对应 row org.h2.mvstore.tx.RollbackDecisionMaker#decide 1.获取 undo log record 里当前存储的旧值 org.h2.mvstore.tx.TransactionStore#openMap 3.获取数据行对应 mvMap(比如 primary key mvMap) org.h2.mvstore.MVMap#operate 回滚数据行 org.h2.mvstore.MVMap#flushAndGetRoot 获取表根节点 org.h2.mvstore.CursorPos#traverseDown 找到数据行 org.h2.mvstore.Page.Leaf#remove 移除数据行 org.h2.mvstore.Page.Leaf#remove 移除 undo log 叶子节点 org.h2.mvstore.tx.TransactionStore#endTransaction org.h2.mvstore.tx.Transaction#setStatus 修改状态 org.h2.engine.SessionLocal#endTransaction org.h2.engine.SessionLocal#unlockAll 释放锁
|
参考