每个事务都有一个对象,这篇文章我们聊聊,事务的对象从哪里来,要到哪里去。
作者:操盛春,爱可生技术专家,公众号『一树一溪』作者,专注于研究 MySQL 和 OceanBase 源码。
爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
本文基于 MySQL 8.0.32 源码,存储引擎为 InnoDB。
InnoDB 读写表中数据的操作都在事务中执行,开始一个事务的方式有两种:
BEGIN
、START TRANSACTION
语句以及它们的扩展形式开始一个事务。这两种方式开始的事务,都用来执行用户 SQL 语句,属于用户事务。
InnoDB 有时候也需要自己执行一些 SQL 语句,为了和用户 SQL 做区分,我们把这些 SQL 称为内部 SQL。
内部 SQL 也需要在事务中执行,执行这些 SQL 的事务就是内部事务。
InnoDB 有几种场景会使用内部事务,以下是其中主要的三种:
InnoDB 用事务池来管理事务对象,用事务池管理器来管理事务池。
不管是用户事务,还是内部事务,真正启动事务之前,都需要通过事务池管理器从某个事务池的事务队列中分配一个事务对象。
已经创建的那些事务池,都放在事务池管理器的 m_pools 数组中。分配事务对象时,先从第 1 个事务池开始,过程是这样的:
分配一个事务对象,得到的是一个出厂设置的对象,这个对象的各属性值都已经是初始状态了。
分配事务对象之后,InnoDB 还会对事务对象的几个属性再做一次初始化工作,把这几个属性再一次设置为初始值,其实就是对这些属性做了重复的赋值操作。
这些属性中,有必要提一下的是事务状态(trx->state
)。出厂设置的事务对象,事务状态是 TRX_STATE_NOT_STARTED
,表示事务还没有开始。
我们执行 show engine innodb status
可能会看到类似下面的内容:
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 281480261177256, not started
0 lock struct(s), heap size 1192, 0 row lock(s)
其中,not started
就来源于事务的 TRX_STATE_NOT_STARTED
状态。
除了给几个属性重复赋值,还会改变另外两个属性的值:
TRX_FORCE_ROLLBACK_DISABLE
标志,防止这个事务被其它线程触发回滚操作。事务后续执行过程中,这个标志可能会被清除,我们就不展开介绍了。我们查询 information_schema.innodb_trx
表,能看到当前正在执行的事务有哪些,这些事务来源于两个链表。
为用户事务分配一个事务对象之后,还有一件非常重要的事,就是把事务对象放入其中一个链表的最前面,代码是这样的:
UT_LIST_ADD_FIRST(trx_sys->mysql_trx_list, trx);
从上面的代码可以看到,这个链表就是 trx_sys->mysql_trx_list
,它只会记录用户事务。
至于内部事务,并不会放入 trx_sys->mysql_trx_list
链表。等到真正启动事务时,事务对象会被放入另一个链表,我们先按下不表,留个悬念,后面的内容会介绍。
InnoDB 把事务分为用户事务和内部事务,给事务分配对象时,会按照这个顺序:
本期问题:InnoDB 怎么没有把内部事务也放入
trx_sys->mysql_trx_list
链表?欢迎大家留言交流。
下期预告:准备那么久,终于要启动 InnoDB 事务了。
更多技术文章,请访问:https://opensource.actionsky.com/
SQLE 是一款全方位的 SQL 质量管理平台,覆盖开发至生产环境的 SQL 审核和管理。支持主流的开源、商业、国产数据库,为开发和运维提供流程自动化能力,提升上线效率,提高数据质量。
类型 | 地址 |
---|---|
版本库 | https://github.com/actiontech/sqle |
文档 | https://actiontech.github.io/sqle-docs/ |
发布信息 | https://github.com/actiontech/sqle/releases |
数据审核插件开发文档 | https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse |