第 02 期 [事务] BEGIN 语句会马上启动事务吗?
聊聊最常用也是最简单的 BEGIN 语句,开始一个事务的过程中都干了什么。
作者:操盛春,爱可生技术专家,公众号『一树一溪』作者,专注于研究 MySQL 和 OceanBase 源码。
爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
BEGIN 语句会马上启动事务吗?
本文基于 MySQL 8.0.32 源码,存储引擎为 InnoDB。
目录 [TOC]
正文
1. BEGIN 语句的七十二变
我们查看官方文档中开始一个事务的语法,会发现还挺复杂:
START TRANSACTION [transaction_characteristic [, transaction_characteristic] ...] transaction_characteristic: { WITH CONSISTENT SNAPSHOT | READ WRITE | READ ONLY } BEGIN [WORK]
上面眼花缭乱的语法,按照各种组合展开之后,可以得到这些 SQL 语句:
/* 1 */ BEGIN /* 2 */ BEGIN WORK /* 3 */ START TRANSACTION /* 4 */ START TRANSACTION READ WRITE /* 5 */ START TRANSACTION READ ONLY /* 6 */ START TRANSACTION WITH CONSISTENT SNAPSHOT /* 7 */ START TRANSACTION WITH CONSISTENT SNAPSHOT, READ WRITE /* 8 */ START TRANSACTION WITH CONSISTENT SNAPSHOT, READ ONLY /* 9 */ START TRANSACTION WITH CONSISTENT SNAPSHOT, READ WRITE, READ ONLY /* 10 */ START TRANSACTION READ WRITE, READ ONLY
其中,语句 1 ~ 8 都能正常执行,语句 9、10 会报语法错误:
(1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1")
语句 9、10 报语法错误,并不是因为 MySQL 不能识别这两种语法,而是识别语法之后进行判断给出的错误提示:
start: START_SYM TRANSACTION_SYM opt_start_transaction_option_list { LEX *lex= Lex; lex->sql_command= SQLCOM_BEGIN; /* READ ONLY and READ WRITE are mutually exclusive. */ if (($3 & MYSQL_START_TRANS_OPT_READ_WRITE) && ($3 & MYSQL_START_TRANS_OPT_READ_ONLY)) { YYTHD->syntax_error(); MYSQL_YYABORT; } lex->start_transaction_opt= $3; } ;
上面是解析 START TRANSACTION 的部分逻辑,通过以上逻辑可以看到,当 START TRANSACTION 同时包含以下两项时:
- MYSQL_START_TRANS_OPT_READ_WRITE
- MYSQL_START_TRANS_OPT_READ_ONLY
MySQL 会通过 YYTHD->syntax_error() 主动抛出一个语法错误,告诉我们不支持这样的语法。
在可以正常执行的语句 1 ~ 8 中:
- 语句 1 ~ 4:用于开始一个新的读写事务。<br /> 语句 5:用于开始一个新的只读事务。<br /> 这两类语句都不需立即创建一致性读视图,事务的启动将延迟至实际需要时。
- 语句 6 ~ 7:用于开始一个新的读写事务。<br /> 语句 8:用于开始一个新的只读事务。<br /> 这两类语句都会先启动事务,随后立即创建一致性读视图。
如果要投票选出我们最常用于开始一个事务的语句,大概非 BEGIN 莫属了。
接下来,我们就用 BEGIN 作为语句 1 ~ 5 的代表,来聊聊开始一个新事务的过程中,MySQL 做的那些事。
2. BEGIN 语句都干什么了?
如果用一个词语描述 BEGIN 语句要做的事,那就是辞旧迎新,展开来说,BEGIN 语句主要做两件事:
- 辞旧:提交老事务。
- 迎新:准备新事务。
2.1 提交老事务
我们先来看一个场景:
在 MySQL 客户端命令行(mysql
)中,我们通过 BEGIN 语句开始了一个事务(事务 1
),并且已经执行了一条 INSERT 语句。
事务 1 还没有提交(即处于活跃状态),我们在同一个连接中又执行了 BEGIN 语句,事务 1 会发生什么?
答案是:事务 1 会被提交。
原因是: MySQL 不支持嵌套事务。事务 1 没有提交的情况下,又要开始一个新事务,事务 1 将无处安放,只能被动提交了。
回到本小节主题,我们来看看 BEGIN 语句提交老事务的流程。
首先,BEGIN 语句会判断当前连接中是否有可能存在未提交事务,判断逻辑为:当前连接的线程是否被打上了 OPTION_NOT_AUTOCOMMIT
或 OPTION_BEGIN
标志位(如下代码所示)。
if (thd->in_multi_stmt_transaction_mode() || ...) { ... } inline bool in_multi_stmt_transaction_mode() const { return variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN); }
只要 variables.option_bits
包含其中一个标志位,就说明当前连接中可能存在未提交事务。
BEGIN 语句想要开始一个新事务,就必须先执行一次提交操作,把可能未提交的事务给提交了(如下代码所示)。
if (thd->in_multi_stmt_transaction_mode() || ...) { ... res = ha_commit_trans(thd, true); }
如果 variables.option_bits
没有包含两个标志位中的任何一个,说明当前连接中没有未提交事务,可以直接开始一个新事务。
2.2 准备新事务
辞旧完事,就该迎新了。
由于 MySQL 一向秉持不铺张浪费的原则,对于资源,能少分配就少分配、能晚分配就晚分配。
启动事务也需要分配资源,遵循不铺张浪费的原则,BEGIN 语句执行过程中,并不会马上启动一个新事务,只会为新事务做一点点准备工作。
这个一点点真的是一点点,你看:
thd->variables.option_bits |= OPTION_BEGIN;
上面的准备工作就是给当前连接的线程打上 OPTION_BEGIN
标志。
有了 OPTION_BEGIN
标志,MySQL 就不会每次执行完一条 SQL 语句就提交事务,而是需要用户发起 commit 语句才提交事务,这样的事务就可以执行多条 SQL 了。
3. 总结
一句话总结:BEGIN 语句执行过程中,要做的事情就是辞旧(提交老事务)迎新(准备新事务),并不会马上启动一个新事务。
本期问题:对于 START TRANSACTION 同时指定 READ WRITE、READ ONLY,除了报错,你还有别的思路解决这个问题吗?欢迎大家留言交流。
下期预告:我是一个事务,请给我一个对象。
更多技术文章,请访问:https://opensource.actionsky.com/
关于 SQLE
SQLE 是一款全方位的 SQL 质量管理平台,覆盖开发至生产环境的 SQL 审核和管理。支持主流的开源、商业、国产数据库,为开发和运维提供流程自动化能力,提升上线效率,提高数据质量。
SQLE 获取

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
社区发布 | 深度求索 670 亿大模型技术报告发布
2024 开年巨献,深度解读 DeepSeek大模型背后的技术秘密.. 一个月前,深度求索开源了670 亿参数的大模型 (DeepSeek LLM 67B) ,在近 40 个中英文榜单上全面超越了700 亿的 LLaMA 2。 全系列模型已开源至 Hugging Face, 无需申请免费商用 ,目前已累积 超 5.8 万次下载 。 https://hf.co/deepseek-ai 今天,我们将 40+ 页的DeepSeek LLM技术报告发布至 Arxiv,并在本文深度解读其后的关键技术。 论文地址:https://arxiv.org/abs/2401.02954 技术报告 Highlights 自建全面Scaling Laws,为模型扩大更好奠基 深入探索了 超参数的Scaling Law s :为选择最佳超参数(Batch Size、 Learning Rate)提供了经验框架 详细论证了 数据质量 对Scaling Laws的影响 :同等数据规模下,数据质量越高,最优参数规模越大 完整的对齐实践细节,全方位的AGI能力评估 对比开源模型(左图),DeepSeek LLM 67B...
- 下一篇
抖音APP如何实现用户生命周期提升
更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群 近日,在火山引擎数智平台在北京举办的“超话数据:企业产品优化分享”的活动上,抖音策略产品经理分享了抖音产品提升用户生命周期的难点及解决办法。 他提到,抖音产品优化涉及到性能、交互、内容和业务等多方面因素,其优化难点主要受用户规模与活跃度影响。抖音目前DAU超6亿,在如此庞大的用户基数下,抖音的优化难点可以概括到三点: 用户规模大,基线高,策略不能一刀切。 优化空间在于少数人群,而非大盘。 同一个策略、交互,数亿用户的反馈不同。 产品优化的传统方法是通过对整体指标进行优化,来综合提升大盘的用户体验。但面对抖音庞大的用户基数,在实践中对大盘用户有用的方法,对于部分人群来说效果并不达预期。综合难点可以分析获知,抖音团队进行产品优化可以分为明确优化性能及其业务表现、明确优化人群、明确产品优化空间、明确实验核心指标及原则,四个步骤进行。 明确优化性能及其业务表现 不同的用户在使用抖音时的体验不同,会对产品产生不同的负向反馈。如果没有及时解决问题优化用户体验,就可能会使用户对抖音产品的价值感走低。传统的产品优化方...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS8安装Docker,最新的服务器搭配容器使用
- Linux系统CentOS6、CentOS7手动修改IP地址
- 2048小游戏-低调大师作品
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS8编译安装MySQL8.0.19
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS7,8上快速安装Gitea,搭建Git服务器