# 海山数据库(He3DB)源码详解:事务块执行过程及内核函数
本文介绍了事务执行过程中,从BEGIN事务开始到事务结束END/ABORT的内核函数执行过程。
前言:
事务SQL语句的执行过程,会先通过事务块函数修改事务块状态,然后根据事务块状态执行不同的事务行为。因此,本章会讲解事务块的开始和结束过程的事务块函数。
事务块控制事务执行的过程:
在讲具体函数之前,有必要在此讲解一下,事务块是如何控制事务行为的。事务管理器中,事务块会根据当前事务状态,来控制具体的事务操作行为,具体流程如下:
- 开始事务块:表示一个新的事务块的开始。
- 检查事务状态:检查当前事务的状态,是否活跃、空闲或处于错误状态。
- 活跃:如果事务处于活跃状态,执行事务操作。
- 执行事务操作:执行具体的事务操作,如插入、更新或删除数据。
- 空闲:如果事务处于空闲状态,等待操作命令。
- 等待操作命令:在事务空闲时等待接收到新的操作命令。
- 接收到操作命令:一旦接收到操作命令,开始执行事务操作。
- 执行事务操作:执行具体的事务操作,如插入、更新或删除数据。
- 操作成功?:检查事务操作是否成功。
- 提交事务:如果操作成功,提交事务。
- 回滚事务:如果操作失败或事务处于错误状态,回滚事务。
- 错误:如果事务处于错误状态,进行回滚操作。
- 回滚事务:如果操作失败或事务处于错误状态,回滚事务。
- 活跃:如果事务处于活跃状态,执行事务操作。
- 结束事务块:表示事务块的结束,此时事务已经提交或回滚。
如何进行事务块操作:
使用 BEGIN
命令可以手动控制启动事务的边界,开始一个新的事务块;
使用 END \COMMIT
命令可以手动控制结束事务,结束一个执行中的事务块;
使用 ABORT \ ROLLBACK
命令可以手动控制放弃回滚事务,结束一个出错的事务块;
当执行这些SQL语句时,系统底层会调用相对应的事务块函数,来修改当前事务块的状态,从而控制具体的事务操作行为。其中,事务块操作的开始和结束分别对应的函数为:
BEGIN
对应的事务块函数为BeginTransactionBlock()
函数;END \ COMMIT
对应的事务块函数为EndTransactionBlock()
函数;ABORT \ ROLLBACK
对应的事务块函数为UserAbortTransactionBlock()
函数。
那么,这些函数的执行流程是什么样的?
BeginTransactionBlock()函数的执行过程:
当终端输入BEGIN或者START TRANSACTION命令时,会开始一个事务块。处理过程首先会调用BeginTransactionBlock()函数。该函数内部主体为一个switch结构,会对枚举类型TBlockState中的所有状态都进行一个判断,并作一个对应的处理。执行过程示意图如下:
-
首先通过全局变量
CurrentTransactionState
获得当前事务块状态的变量;TransactionState s = CurrentTransactionState;
-
然后通过
switch-case
结构,根据当前事务块状态做对应的操作,其中有包括:
- 如果当前事务块状态为TBLOCK_STARTED,则修改为TBLOCK_BEGIN;
case TBLOCK_STARTED: s->blockState = TBLOCK_BEGIN; break;
- 如果当前事务块状态为TBLOCK_IMPLICIT_INPROGRESS,则修改为TBLOCK_BEGIN;
case TBLOCK_IMPLICIT_INPROGRESS: s->blockState = TBLOCK_BEGIN; break;
- 如果当前事务块状态为TBLOCK_INPROGRESS、TBLOCK_PARALLEL_INPROGRESS、TBLOCK_SUBINPROGRESS、TBLOCK_ABORT和TBLOCK_SUBABORT,会进行WARNING报警,但是不会影响执行过程,可以继续执行;
case TBLOCK_INPROGRESS: case TBLOCK_PARALLEL_INPROGRESS: case TBLOCK_SUBINPROGRESS: case TBLOCK_ABORT: case TBLOCK_SUBABORT: ereport(WARNING, (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), errmsg("there is already a transaction in progress"))); break;
- 如果当前事务块状态为上述提到的其他状态,则直接报FATAL错误,直接退出事务块过程;
case TBLOCK_DEFAULT: case TBLOCK_BEGIN: case TBLOCK_SUBBEGIN: case TBLOCK_END: case TBLOCK_SUBRELEASE: case TBLOCK_SUBCOMMIT: case TBLOCK_ABORT_END: case TBLOCK_SUBABORT_END: case TBLOCK_ABORT_PENDING: case TBLOCK_SUBABORT_PENDING: case TBLOCK_SUBRESTART: case TBLOCK_SUBABORT_RESTART: case TBLOCK_PREPARE: elog(FATAL, "BeginTransactionBlock: unexpected state %s", BlockStateAsString(s->blockState)); break;
以上,就是BeginTransactionBlock()函数的全部执行过程。
EndTransactionBlock()函数的执行过程:
当终端输入COMMIT或者EDN语句时,这时一个事务块会发起提交或者结束,如果输入END,正确结束为提交,错误结束为回滚。处理过程首先会调用EndTransactionBlock()函数,并根据返回值判断是否时错误结束发生回滚。EndTransactionBlock()函数和BeginTransactionBlock()十分相似,内部主要是一个swith结构,这里直接说执行流程:
-
首先通过全局变量
CurrentTransactionState
获得当前事务块状态的变量,并定义返回值bool变量result;TransactionState s = CurrentTransactionState; bool result = false;
-
然后通过
switch-case
结构,根据当前事务块状态做对应的操作,其中有包括:
- 如果当前事务块状态为TBLOCK_INPROGRESS,则修改为TBLOCK_END,并将变量result赋值为true;
case</