从Laravel,Yii,Thinkphp中学习php 操作数据库的事务嵌套

最近维护历史代码,使用的是phalapi 最初版本开发,数据库操作使用的是notorm。notorm本身不支持事务嵌套,但是在开发过程中,多个操作进行拆分,根据不同业务不同进行调用,必然会设计到多个事务嵌套在一起的问题。举个栗子:

1) 公共模块A,更新用户的账户余额,添加流水记录操作。

2) 模块B,根据用户的操作(消费或充值)根据活动配置赠送相应的优惠券。

基础业务A模块就够用了,但是出现一些业务活动的时候,需要在A成功之后调用B模块,只有两个操作成功之后才完整提交事务。要实现这样的功能,无非两种方式:

1) 模块内部不加事务,事务控制统一交给调用方。谁调用,谁负责事务。内部模块只提供内部模块执行结果。

2) 模块内部控制事务,外部调用只需知道内部执行是否成功。

如果设计的合理,还是比较倾向于使用第一种方案。但是不可否认,你无法确定你的调用模块会不会再被其他人调用,最终结果又演变成第二种方案。因此底层还是需要支持事务嵌套。

嵌套事务的核心思想就是添加一个计数器,第一次开启事务,最后一次提交或回滚执行数据库操作,其他情况只是更新计数器数值。分别看一看几个现有框架如何设计数据库事务嵌套操作:

1) Laravel

Laravel与事务相关操作封装在 Illuminate\Database\Concerns\ManagesTransactions当中。

2) Yii2

Yii2的事务操作也是有一个单独文件进行封装,yii\db\Transaction。

3) Thinkphp5

Thinkphp5的事务操作并没有独立分开,直接在数据库连接类当中think\db\Connection;

三个框架都是通过计数器以及数据库本身的"部分事务"支持嵌套事务的操作。MYSQL 中通过 savepoint 的方式来实现只提交事务的一部分。操作流程大体分一下三步

1) 开启事务,检查计数器是否是第一次开启,如果是则执行pdo开启事务,不是则修改计数器的值,同时根据是否支持部分事务,执行pdo savepoint操作。

2) 事务提交,检查计数器是否是最外层事务,是则执行pdo事务提交操作,否则计数器减1

3) 事务回滚,检查计算器是否是最外层操作,是则执行pdo事务回滚,否则计数器减1,同时根据是否支持部分事务,执行pdo rollbak to savepoint 操作

虽然整体思路一样,但是三个框架根据自身的特定,代码设计抽象程度不一样。从这个相同的功能,也能够很好的体会三个框架不同的设计方式。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180905G1JZUY00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券