BEGIN 语句会马上启动事务吗?


爱可生开源社区
爱可生开源社区 2024-01-10 17:12:45 52097
分类专栏: 资讯

目录

  • 1. BEGIN 语句的七十二变

  • 2. BEGIN 语句都干什么了?

    • 2.1 提交老事务

    • 2.2 准备新事务

  • 3. 总结

正文

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:用于开始一个新的读写事务。
    语句 5:用于开始一个新的只读事务。
    这两类语句都不需立即创建一致性读视图,事务的启动将延迟至实际需要时。
  • 语句 6 ~ 7:用于开始一个新的读写事务。
    语句 8:用于开始一个新的只读事务。
    这两类语句都会先启动事务,随后立即创建一致性读视图。

如果要投票选出我们最常用于开始一个事务的语句,大概非 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 语句执行过程中,要做的事情就是辞旧(提交老事务)迎新(准备新事务),并不会马上启动一个新事务。

网站声明:如果转载,请联系本站管理员。否则一切后果自行承担。

本文链接:https://www.xckfsq.com/news/show.html?id=35024
赞同 1
评论 0 条
爱可生开源社区L3
粉丝 0 发表 27 + 关注 私信
上周热门
如何使用 StarRocks 管理和优化数据湖中的数据?  2935
【软件正版化】软件正版化工作要点  2854
统信UOS试玩黑神话:悟空  2811
信刻光盘安全隔离与信息交换系统  2702
镜舟科技与中启乘数科技达成战略合作,共筑数据服务新生态  1235
grub引导程序无法找到指定设备和分区  1205
点击报名 | 京东2025校招进校行程预告  162
华为全联接大会2024丨软通动力分论坛精彩议程抢先看!  160
2024海洋能源产业融合发展论坛暨博览会同期活动-海洋能源与数字化智能化论坛成功举办  156
金山办公2024算法挑战赛 | 报名截止日期更新  153
本周热议
我的信创开放社区兼职赚钱历程 40
今天你签到了吗? 27
信创开放社区邀请他人注册的具体步骤如下 15
如何玩转信创开放社区—从小白进阶到专家 15
方德桌面操作系统 14
我有15积分有什么用? 13
用抖音玩法闯信创开放社区——用平台宣传企业产品服务 13
如何让你先人一步获得悬赏问题信息?(创作者必看) 12
2024中国信创产业发展大会暨中国信息科技创新与应用博览会 9
中央国家机关政府采购中心:应当将CPU、操作系统符合安全可靠测评要求纳入采购需求 8

加入交流群

请使用微信扫一扫!