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;
    }
}

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

第一次开启事务则真正调用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);

}
执行事务回滚时事务次数统一减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;

}
只有事务次数为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
目录
相关文章
|
1月前
|
SQL 关系型数据库 MySQL
MySQL事务日志-Undo Log工作原理分析
事务的持久性是交由Redo Log来保证,原子性则是交由Undo Log来保证。如果事务中的SQL执行到一半出现错误,需要把前面已经执行过的SQL撤销以达到原子性的目的,这个过程也叫做"回滚",所以Undo Log也叫回滚日志。
MySQL事务日志-Undo Log工作原理分析
|
2月前
|
SQL 安全 关系型数据库
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
事务是MySQL中一组不可分割的操作集合,确保所有操作要么全部成功,要么全部失败。本文利用SQL演示并总结了事务操作、事务四大特性、并发事务问题、事务隔离级别。
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
|
2月前
|
SQL 关系型数据库 MySQL
MySQL进阶突击系列(04)事务隔离级别、AICD、CAP、BASE原则一直搞不懂? | 看这篇就够了
本文详细介绍了数据库事务的四大特性(AICD原则),包括原子性、隔离性、一致性和持久性,并深入探讨了事务并发问题与隔离级别。同时,文章还讲解了分布式系统中的CAP理论及其不可能三角关系,以及BASE原则在分布式系统设计中的应用。通过具体案例和图解,帮助读者理解事务处理的核心概念和最佳实践,为应对相关技术面试提供了全面的知识准备。
|
2月前
|
存储 关系型数据库 MySQL
PHP与MySQL动态网站开发:从基础到实践####
本文将深入探讨PHP与MySQL的结合使用,展示如何构建一个动态网站。通过一系列实例和代码片段,我们将逐步了解数据库连接、数据操作、用户输入处理及安全防护等关键技术点。无论您是初学者还是有经验的开发者,都能从中获益匪浅。 ####
|
3月前
|
安全 关系型数据库 MySQL
PHP与MySQL动态网站开发实战指南####
——深入探索LAMP栈下的高效数据交互与处理技巧 ####
|
3月前
|
关系型数据库 MySQL PHP
PHP与MySQL动态网站开发实战指南####
深入探索PHP与MySQL的协同工作机制,本文旨在通过一系列实战案例,揭示构建高效、稳定且用户友好的动态网站的秘诀。从环境搭建到数据交互,再到最佳实践分享,本文为开发者提供了一条清晰的学习路径,助力其在LAMP(Linux, Apache, MySQL, PHP/Perl/Python)栈上实现技术飞跃。 ####
|
2月前
|
关系型数据库 MySQL PHP
php实现一个简单的MySQL分页
通过本文的详细步骤和代码示例,我们实现了一个简单的PHP MySQL分页功能。主要步骤包括计算总记录数、设置分页参数、查询当前页的数据以及生成分页链接。这种分页方式适用于大多数Web应用,能够有效提升用户体验和页面响应速度。
65 4
|
3月前
|
关系型数据库 MySQL PHP
PHP与MySQL的无缝集成:构建动态网站的艺术####
本文将深入探讨PHP与MySQL如何携手合作,为开发者提供一套强大的工具集,以构建高效、动态且用户友好的网站。不同于传统的摘要概述,本文将以一个生动的案例引入,逐步揭示两者结合的魅力所在,最终展示如何通过简单几步实现数据驱动的Web应用开发。 ####
|
3月前
|
SQL 关系型数据库 MySQL
PHP与MySQL的高效协同开发策略####
本文深入探讨了PHP与MySQL在Web开发中的协同工作机制,通过优化配置、最佳实践和高级技巧,展示了如何提升数据库交互性能,确保数据安全,并促进代码可维护性。我们将从环境搭建讲起,逐步深入到查询优化、事务管理、安全防护及性能调优等核心环节,为开发者提供一套实战驱动的解决方案框架。 ####
|
3月前
|
关系型数据库 MySQL
mysql事务特性
原子性:一个事务内的操作统一成功或失败 一致性:事务前后的数据总量不变 隔离性:事务与事务之间相互不影响 持久性:事务一旦提交发生的改变不可逆

热门文章

最新文章