共计 1087 个字符,预计需要花费 3 分钟才能阅读完成。
前言:
在咱们平时做的一个我的项目中,线上环境忽然发现数据库被锁住。导致很多无关数据插入和批改的接口全都瘫痪,我的项目基于 ThinkPHP5.1。报错的时候,咱们发现了一条 sql 谬误日志,如下。
依据错误信息提醒,是说有一个事务回滚时没有找到 savepoint 的暂存点。所以问题应该是事务嵌套导致的,目前 ThinkPHP5 封装的数据层办法是有对事务嵌套进行解决。而 MYSQL 到底支不反对事务嵌套呢?伪代码如下。
执行完后呈现了操作 1 的数据真正写入,只有操作 2 的数据回滚了。在第一个事务没有提交或回滚时,再开启第二个事务时,会主动提交第一个事务。这显著不合乎心理预期,而且也无奈回滚一部分操作。首先,调用屡次 begin 的写法,在 MySQL 里必定是无奈首先事务嵌套的。
抱着疑难,我去网上也查了很多相似的问题。却意外的发现对于“解决事务嵌套的办法”都如此的雷同,清一色的“开启事务时候应用单例,查看事务是否存在”。(蒙圈……)
持续回到 MYSQL 是否反对事务嵌套,最初我理解到 MySQL 中有一个叫 savepoint 和 rollback to 的语句。于是我棘手举了个例子。
下面有 3 张表,别离有不同的更新操作和最初的插入。然而最初只回滚到 P1,执行完 commit 后,我发现只有 p1 地位的操作做了更新,前面的批改和插入全都没失效。可能 savepoint 和 rollback to 语句并不能称之为事务嵌套,也不能说 MySQL 是反对还是不反对事务嵌套。总之通过 savepoint 和 rollback to,是能够用来达到一些事务嵌套个性的。
依据咱们我的项目的日志,我也试着复现一下,成心 rollback to 到一个不存在的点上,最初 commit 时发现,数据库的第一条 sql 批改了,前面插入语句也增加胜利了。
ThinkPHP5.1
所以再回到 ThinkPHP5 框架实现的事务嵌套,于是我关上了框架的 Connection 抽象类。最次要的就是上面局部了。
1. 开启事务。
开启事务的局部加了次数累加,只有在代码块中应用了 transaction 就会被记录并叠加,当只有 1 时,才执行 sql 的 begin,否则就 savepoint 记录一个保留点。
2. 提交事务。
判断了只有等于 1 才对事务进行提交,也就是在代码中最初面的 commit 才失效,应用一次减一次嵌套计数。initConnect 办法次要是对分布式数据库和单机对读写连贯的判断。
3. 回滚事务。
回滚次要也是当计数等于 1 才让 sql 执行 rollback,否则 (也就是嵌套了) 就让连贯资源回滚到执行的保留点。它外面的就是应用的 rollback to p1 语句的。