laravel mysql 事务_关于 MySQL 的嵌套事务

MySQL事务

事务

事务的概念就不介绍了, 它的目的是解决ACID问题.

MySQL中的事务必须是InnoDB、Berkeley DB引擎,myisam不支持, 新出了一个memory, 貌似也是不支持的, 大家可以查查。

MySQL默认是autocommit=1,也就是说默认是立即提交,如果想开启事务,先设置autocommit=0,然后用START TRANSACTION、 COMMIT、 ROLLBACK来使用具体的事务。

你可能会有一个疑问: 查询会不会开事务?

根据上面两点可以得出, 如果你在INNODB事务引擎下, 并且autocommit=1 (默认值), 答案是会, 否则不会. 其他引擎不支持事务, 这个问题也不存在.

这时候你可能又有另外一个疑问: 我只是执行单个查询语句, 为什么要开事务?

如果你一次执行单条查询语句,则没有必要启用事务支持,数据库默认支持SQL执行期间的读一致性;

如果你一次执行多条查询语句,例如统计查询,报表查询,在这种场景下,多条查询SQL必须保证整体的读一致性,否则,在前条SQL查询之后,后条SQL查询之前,数据被其他用户改变,则该次整体的统计查询将会出现读数据不一致的状态,此时,应该启用事务支持。

==测试数据表结构==

id

stock1

109

START TRANSACTION;

SAVEPOINT a;

UPDATE `user` SET stock = 1 WHERE id = 1;

SAVEPOINT b;

UPDATE `user` SET stock = 2 WHERE id = 1;

ROLLBACK TO b;

commit;

执行的代码,会发有数据表中id=1的行stock值被修改为1。

解读一下代码

开启事物

建立保存点a

更新数据stock为1

建立保存点b(此时id=1的数据stock=1)

更新stock为2

回滚至savepoint b

提交事物

粗读这段代码,即可以知道,savepoint是可以在事务进行中建立保存点,类似游戏中的存档一样,但是有个不一样的地方就是savepoint的持有者是事务,当事务commit或者是完全rollback之后,savepoint就会释放。

THINKPHP

PHP框架THINKPHP5的嵌套事务处理策略: 如果开启了supportSavepoint, 则利用SAVEPOINT来等价子事务, 否则啥也不干, MySQL驱动下默认开启

这产生了一个很重要的结论: 子事务的回滚不会导致事务回滚, 只有第一个事务的回滚才是真正的ROLLBACK

==TP5.1关于嵌套事务的实现源码截取==

/**

* 启动事务

* @access public

* @return void

* @throws \PDOException

* @throws \Exception

*/

public function startTrans()

{

$this->initConnect(true);

if (!$this->linkID) {

return false;

}

++$this->transTimes;

try {

if (1 == $this->transTimes) {

$this->linkID->beginTransaction();

} elseif ($this->transTimes > 1 && $this->supportSavepoint()) {

$this->linkID->exec(

$this->parseSavepoint('trans' . $this->transTimes)

);

}

} catch (\Exception $e) {

if ($this->isBreak($e)) {

--$this->transTimes;

return $this->close()->startTrans();

}

throw $e;

}

}

/**

* 事务回滚

* @access public

* @return void

* @throws PDOException

*/

public function rollback()

{

$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);

}

/**

* 用于非自动提交状态下面的查询提交

* @access public

* @return void

* @throws PDOException

*/

public function commit()

{

$this->initConnect(true);

if (1 == $this->transTimes) {

$this->linkID->commit();

}

--$this->transTimes;

}

/**

* 是否支持事务嵌套

* @return bool

*/

protected function supportSavepoint()

{

return false;

}

/**

* 生成定义保存点的SQL

* @access protected

* @param $name

* @return string

*/

protected function parseSavepoint($name)

{

return 'SAVEPOINT ' . $name;

}

==从TP的实现源码上面可以知道,TP框架在出现嵌套事务时,处理方法就是采用savepoint的策略。startTrans 与 rollback方法都不是直接执行mysql的rollback。他执行分两步==

判断是不是第一次开启事务,如果是的话就开启事务,否则这是单纯的执行savepoint方法。

回滚rollback的时候也是同理,只有当时最外层的事务执行rollback时,他才会执行mysql的rollback,否则都是rollback to savepoint。

本作品采用《CC 协议》,转载必须注明作者和本文链接

大人中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值