>我们做项目的过程中,难免无意中会在事务中嵌套了事务。
比如封装了一个funcA()方法,funcA()方法里包含了一个事务。然后我们在业务代码里写了一个事务,且在事务中调用了funcA()。这样就形成了事务嵌套。
但是在[MySQL官方文档](https://dev.mysql.com/doc/refman/8.0/en/implicit-commit.html)中有明确的说明不支持嵌套事务
![](http://image.gwalker.cn/article_2018-12-186445c185d0ddb2bb29053.jpg)
也就是说,当执行一个START TRANSACTION指令时,会隐式的执行一个commit操作。不能进行事务嵌套。
现在一些注流PHP开发框架,为了解决方法调用产生的mysql事务嵌套问题。对这个进行了处理。处理方法一般是定义了一个**"务指令数"记数器**。把被嵌套的事务,到消掉。Thinkphp源码原理实现如下:
```php
abstract class Driver
{
// 事务指令数
protected $transTimes = 0;
....
/**
* 启动事务
* @access public
* @return void
*/
public function startTrans()
{
$this->initConnect(true);
if (!$this->_linkID) {
return false;
}
//数据rollback 支持
if (0 == $this->transTimes) {
// 记录当前操作PDO
$this->transPdo = $this->_linkID;
$this->_linkID->beginTransaction();
}
$this->transTimes++;
return;
}
/**
* 用于非自动提交状态下面的查询提交
* @access public
* @return boolean
*/
public function commit()
{
if (1 == $this->transTimes) {
// 由嵌套事物的最外层进行提交
$result = $this->_linkID->commit();
$this->transTimes = 0;
$this->transPdo = null;
if (!$result) {
$this->error();
return false;
}
} else {
$this->transTimes = $this->transTimes <= 0 ? 0 : $this->transTimes - 1;
}
return true;
}
/**
* 事务回滚
* @access public
* @return boolean
*/
public function rollback()
{
if ($this->transTimes > 0) {
$result = $this->_linkID->rollback();
$this->transTimes = 0;
$this->transPdo = null;
if (!$result) {
$this->error();
return false;
}
}
return true;
}
...
}
```