MYSQL事务嵌套,PHP事务嵌套,THINKPHP事务嵌套

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: MYSQL事务嵌套,PHP事务嵌套,THINKPHP事务嵌套

最近有在追踪一个tp3的事务问题,正好看到事务嵌套的问题,于是整理了出来,本来想等待同事整理,白嫖他,结果等了个寂寞。

(1).参考事务嵌套的错误SQL:

事务1开启

BEGIN;

## 事务1修改数据
UPDATE hqjf_job_num SET wx_uname='蒋琦1024' where id = 602;

### 事务2开启
BEGIN;

### 事务2提交
COMMIT;

事务1回滚

ROLLBACK;
我们期望的结果:update语句不会执行成功,实际执行成功了

出现问题的原因:BEGIN语句会隐式的执行事务提交,相当于第二个BEGIN执行的时候提交了第一个事务.

(2).哪些SQL语法会隐式事务提交事务呢?

参考Mysql官方文档:

https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html

(2.1).DDL

ALTER DATABASE ... UPGRADE DATA DIRECTORY NAME, ALTER EVENT, ALTER PROCEDURE, ALTER SERVER, ALTER TABLE, ALTER TABLESPACE, ALTER VIEW, CREATE DATABASE, CREATE EVENT, CREATE INDEX, CREATE PROCEDURE, CREATE SERVER, CREATE TABLE, CREATE TABLESPACE, CREATE TRIGGER, CREATE VIEW, DROP DATABASE, DROP EVENT, DROP INDEX, DROP PROCEDURE, DROP SERVER, DROP TABLE, DROP TABLESPACE, DROP TRIGGER, DROP VIEW, INSTALL PLUGIN, RENAME TABLE, TRUNCATE TABLE, UNINSTALL PLUGIN.
(2.2).USER|MODIFY TABLES

ALTER USER, CREATE USER, DROP USER, GRANT, RENAME USER, REVOKE, SET PASSWORD.
(2.3).TRANSACTION|LOCK TABLES

BEGIN, LOCK TABLES, (if the value is not already 1), START TRANSACTION, UNLOCK TABLES. SET autocommit = 1,UNLOCK TABLES
(2.4).DATA LOADING STATEMENTS

LOAD DATA
(2.5).ADMINISTRATIVE STATEMENTS

ANALYZE TABLE, CACHE INDEX, CHECK TABLE, FLUSH, LOAD INDEX INTO CACHE, OPTIMIZE TABLE, REPAIR TABLE, RESET
(2.6).REPLICATION CONTROL STATEMENTS

START SLAVE, STOP SLAVE, RESET SLAVE, CHANGE MASTER TO
好家伙原来这多SQL操作都会隐式提交事务

同时上面的文档中提到:

Transactions cannot be nested. This is a consequence of the implicit commit performed for any current transaction when you issue a START TRANSACTION statement or one of its synonyms.
事务不能嵌套。 这是当您发出 START TRANSACTION 语句或其同义词之一时对任何当前事务执行的隐式提交的结果。

(3).设置autocommit并不能解决上面的事务嵌套问题,好好了解下autocommit到底是啥

首先要知道什么叫自动提交。就是自动提交事务啦。瓜娃子。

(3.1).假设开启事务自动提交的时候,你执行一个SQL如下:

UPDATE hqjf_job_num SET wx_uname='蒋琦104' where id = 6956;
实际上已经等价于执行了如下SQL:

BEGIN;
UPDATE hqjf_job_num SET wx_uname='蒋琦104' where id = 6956;
COMMIT;
只不过是MYSQL帮你的SQL自动加了事务并且提交了。

如果你开启了事务自动提交且自己使用了事务操作,MYSQL就会乖乖听你的,不会乱自动提交,除非你自己隐式提交。

(3.2).假设关闭事务自动提交的时候,你执行一个SQL如下:

UPDATE hqjf_job_num SET wx_uname='蒋琦104' where id = 6956;
实际上根本不会执行成功,关闭事务自动提交后MYSQL要求你必须自己手动提交事务,否则SQL没有提交也就不会更新咯

老高你的内容我看不懂,给我推荐1个详细的autocomit的文章,好的,给你。直达地址:https://blog.csdn.net/wx145/article/details/82740737

上面我们得出的结论是MYSQL是不支持事务嵌套的,特别注意是不支持的,不支持的,不支持的!别看其他文章瞎说,看官方文档。

(4).MYSQL不支持事务嵌套,如果模拟事务嵌套的效果

(4.1).例子SQL:

开启事务

BEGIN;

建立事务保存点a

SAVEPOINT a;

更新数据名称为1024

UPDATE hqjf_job_num SET wx_uname='1024' WHERE id=7638;

建立事务保存点b

SAVEPOINT b;

更新数据名称为2048

UPDATE hqjf_job_num SET wx_uname='2048' WHERE id=7638;

建立事务保存点d

SAVEPOINT c;

回滚到事务保存点

ROLLBACK TO SAVEPOINT a;

提交事务

COMMIT;
假设以上数据的原始wx_uname的原始值为空

ROLLBACK TO SAVEPOINT a;则数据不会修改
ROLLBACK TO SAVEPOINT b;则数据会被修改为1024
ROLLBACK TO SAVEPOINT c;则数据会被修改为2048
看看上面的SQL代码的执行顺序吧:

上面的SQL在执行到ROLLBACK TO SAVEPOINT a的时候回跳到建立事务保存点a的位置,然后执行剩下的COMIT语句,因此示例的SQL不会修改任何数据

(5).PHP框架中解决MYSQL事务嵌套的方案(TP6)

开启事务示例:

/**

  • 启动事务
  • @access public
  • @return void
  • @throws \PDOException
  • @throws \Exception

*/
public function startTrans(): void
{

try {
    $this->initConnect(true);
    ++$this->transTimes;
    if (1 == $this->transTimes) {
        $this->linkID->beginTransaction();
    } elseif ($this->transTimes > 1 && $this->supportSavepoint()) {
        $this->linkID->exec(
            $this->parseSavepoint('trans' . $this->transTimes)
        );
    }
    $this->reConnectTimes = 0;
} catch (\Throwable | \Exception $e) {
    if ($this->transTimes === 1 && $this->reConnectTimes < 4 && $this->isBreak($e)) {
        --$this->transTimes;
        ++$this->reConnectTimes;
        $this->close()->startTrans();
    } else {
        if ($this->isBreak($e)) {
            // 尝试对事务计数进行重置
            $this->transTimes = 0;
        }
        throw $e;
    }
}
AI 代码解读

}
开启事务时统一递增事务次数

第一次开启事务则真正调用MYSQL开启事务

第二次或以上开启事务分情况:支持savepoint时调用MYSQL创建事务保存点,不支持时则相当于啥也不干,

执行事务回滚示例:

/**

  • 事务回滚
  • @access public
  • @return void
  • @throws \PDOException

*/
public function rollback(): void
{

$this->initConnect(true);
if (1 == $this->transTimes) {
    $this->linkID->rollBack();
} elseif ($this->transTimes > 1 && $this->supportSavepoint()) {
    $this->linkID->exec(
        $this->parseSavepointRollBack('trans' . $this->transTimes)
    );
}
$this->transTimes = max(0, $this->transTimes - 1);
AI 代码解读

}
执行事务回滚时事务次数统一减1

如果事务次数为1则真正提交MYSQL让事务回滚

如果事务次数大于1并且支持savepoint则回滚事务到事务保存点

执行事务提交的示例:

/**

  • 用于非自动提交状态下面的查询提交
  • @access public
  • @return void
  • @throws \PDOException

*/
public function commit(): void
{

$this->initConnect(true);
if (1 == $this->transTimes) {
    $this->linkID->commit();
}
--$this->transTimes;
AI 代码解读

}
只有事务次数为1的时候才会真正提交MYSQL事务

通过框架层的支持,你虽然包含了多层事务,但是本质上你只会真正开启1次事务,提交1次事务,配合savepoint实现事务嵌套的效果。和上面我们模拟事务嵌套的效果一致。

我看到很多PHP事务嵌套没有使用savepoint的实现,严格来说不算是事务嵌套,比如下面的问题:

// 开启主事务
Db::startTrans();
// 开启子事务
Db::startTrans();
// 执行UPDATE语句
// 回滚子事务
Db::rollback();
// 提交主事务
Db::rollback();
最终结果导致主事务提交后子事务的SQL也执行了,因为子事务开启和回滚是虚拟的,什么也没做。当然部分实现中只要子事务回滚强制让主事务也回滚,这样失去的嵌套的意义。

所以支持saveponit才能实现真正的框架层事务嵌套。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
打赏
0
0
0
0
2
分享
相关文章
MySQL底层概述—9.ACID与事务
本文介绍了数据库事务的ACID特性(原子性、一致性、隔离性、持久性),以及事务控制的演进过程,包括排队、排它锁、读写锁和MVCC(多版本并发控制)。文章详细解释了每个特性的含义及其在MySQL中的实现方式,并探讨了事务隔离级别的类型及其实现机制。重点内容包括:ACID特性(原子性、持久性、隔离性和一致性的定义及其实现方式)、事务控制演进(从简单的全局排队到复杂的MVCC,逐步提升并发性能)、MVCC机制(通过undo log多版本链和Read View实现高效并发控制)、事务隔离级别(析了四种隔离级别(读未提交、读已提交、可重复读、可串行化)的特点及适用场景)、隔离级别与锁的关系。
源码编译安装LAMP(HTTP服务,MYSQL ,PHP,以及bbs论坛)
通过以上步骤,你可以成功地在一台Linux服务器上从源码编译并安装LAMP环境,并配置一个BBS论坛(Discuz!)。这些步骤涵盖了从安装依赖、下载源代码、配置编译到安装完成的所有细节。每个命令的解释确保了过程的透明度,使即使是非专业人士也能够理解整个流程。
40 18
ThinkPHP框架show columns引发mysql性能问题
ThinkPHP框架的show columns引发mysql性能问题,结尾有关闭方式。
34 13
如何排查和解决PHP连接数据库MYSQL失败写锁的问题
通过本文的介绍,您可以系统地了解如何排查和解决PHP连接MySQL数据库失败及写锁问题。通过检查配置、确保服务启动、调整防火墙设置和用户权限,以及识别和解决长时间运行的事务和死锁问题,可以有效地保障应用的稳定运行。
151 25
PHP与MySQL动态网站开发实战指南####
【10月更文挑战第21天】 本文将深入浅出地探讨如何使用PHP与MySQL构建一个动态网站,从环境搭建到项目部署,全程实战演示。无论你是编程新手还是希望巩固Web开发技能的老手,都能在这篇文章中找到实用的技巧和启发。我们将一起探索如何通过PHP处理用户请求,利用MySQL存储数据,并最终呈现动态内容给用户,打造属于自己的在线平台。 ####
161 0
MySQL事务日志-Undo Log工作原理分析
事务的持久性是交由Redo Log来保证,原子性则是交由Undo Log来保证。如果事务中的SQL执行到一半出现错误,需要把前面已经执行过的SQL撤销以达到原子性的目的,这个过程也叫做"回滚",所以Undo Log也叫回滚日志。
131 7
MySQL事务日志-Undo Log工作原理分析
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
事务是MySQL中一组不可分割的操作集合,确保所有操作要么全部成功,要么全部失败。本文利用SQL演示并总结了事务操作、事务四大特性、并发事务问题、事务隔离级别。
1167 2
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
MySQL进阶突击系列(04)事务隔离级别、AICD、CAP、BASE原则一直搞不懂? | 看这篇就够了
本文详细介绍了数据库事务的四大特性(AICD原则),包括原子性、隔离性、一致性和持久性,并深入探讨了事务并发问题与隔离级别。同时,文章还讲解了分布式系统中的CAP理论及其不可能三角关系,以及BASE原则在分布式系统设计中的应用。通过具体案例和图解,帮助读者理解事务处理的核心概念和最佳实践,为应对相关技术面试提供了全面的知识准备。
PHP与MySQL动态网站开发实战指南####
——深入探索LAMP栈下的高效数据交互与处理技巧 ####
PHP与MySQL动态网站开发:从基础到实践####
本文将深入探讨PHP与MySQL的结合使用,展示如何构建一个动态网站。通过一系列实例和代码片段,我们将逐步了解数据库连接、数据操作、用户输入处理及安全防护等关键技术点。无论您是初学者还是有经验的开发者,都能从中获益匪浅。 ####
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等