Yii2开发技巧 使用类似闭包的方式封装事务
在控制器中执行事务的时候,一般的代码如下:
$transaction = Yii::$app->db->beginTransaction();
try {
//一些业务代码
$transaction->commit();
} catch (\Exception $e) {
$transaction->rollBack();
throw $e;
}
于是我在想,这个代码结构,只有//一些业务代码 这一部分是不一样,却要重复很多遍,这一不是很冗余吗? 而且 不!好!看!,于是我试着寻找解决方法,一开始在stackflow找到一个类似的提问,有方案是在model里做封装,但是这样做有一定问题,如产生嵌套事务等,有兴趣的可以点击这里查看该问答。
我们的Yii框架给出了一个方法transaction,乍一看好像不能解决传参的问题,我们先不管,往下看,该方法调用方式如下:
Yii::$app->db->transaction(function() {
//一些业务代码
});
我们来看一下这个方法的源码
/**
* Executes callback provided in a transaction.
*
* @param callable $callback a valid PHP callback that performs the job. Accepts connection instance as parameter.
* @param string|null $isolationLevel The isolation level to use for this transaction.
* See [[Transaction::begin()]] for details.
* @throws \Exception|\Throwable if there is any exception during query. In this case the transaction will be rolled back.
* @return mixed result of callback function
*/
public function transaction(callable $callback, $isolationLevel = null)
{
$transaction = $this->beginTransaction($isolationLevel);
$level = $transaction->level;
try {
$result = call_user_func($callback, $this);
if ($transaction->isActive && $transaction->level === $level) {
$transaction->commit();
}
} catch (\Exception $e) {
$this->rollbackTransactionOnLevel($transaction, $level);
throw $e;
} catch (\Throwable $e) {
$this->rollbackTransactionOnLevel($transaction, $level);
throw $e;
}
return $result;
}
这个方法接受一个回调函数和事务的隔离级别,
从这里我们看出,这个方法虽然解决重复代码,却还有几个问题没有解决:
第一,这个方法抛出的异常我们需要在接收外面处理,我们不可能直接抛出,这样对客户端很不友好。
第二:没有记录日志的行为,即使出了问题也不容易排除。
第三:其实还是第一个问题,如果我们需要对每个异常做处理,在transaction方法外再嵌套一层try...catch...,那么和没有封装好像没什么区别?
根据方法可扩展不可修改的原则,我们应该在自己公共方法里对这个方法进行重载,重载代码如下:
public static function TransactionExecute(callable $function,$level=null)
{
try{
\Yii::$app->db->transaction($function,$level);
}catch (\Exception $e){
//记录日志
\Yii::error($e->getMessage());
//这里可以理解成抛出自定义的异常类。
(new self())->returnWayTip(1004, 'trans异常错误');
}
}
然后回到如何传参的问题,我们可以使用闭包,贴一段伪代码,如下:
//执行事务
PublicFunction::TransactionExecute(function () use ($token_reward, $reward_info) {
//业务代码
$token_reward->save(0);
MsgHelper::send($reward_info['post_id'], MsgHelper::SOMEONE_FINISH_REWARD, $reward_info);
});
大功告成,代码看起来有没有更好看呢?
如有问题,欢迎指教。
原文地址:https://segmentfault.com/a/1190000015998299
Yii2开发技巧 使用类似闭包的方式封装事务的更多相关文章
- 5-MySQL DBA笔记-开发技巧
第5章 开发技巧 本章将介绍一些和数据库相关的开发技巧.由于开发领域很广,这里只选取部分比较常见的小技巧.5.1 存储树形数据 有时我们需要保存一些树形的数据结构,比如组织架构.话题讨论.知识管理.商 ...
- thinkphp开发技巧经验分享
thinkphp开发技巧经验分享 www.111cn.net 编辑:flyfox 来源:转载 这里我给大家总结一个朋友学习thinkphp时的一些笔记了,从变量到内置模板引擎及系统变量等等的笔记了,同 ...
- iOS开发技巧系列---详解KVC(我告诉你KVC的一切)
KVC(Key-value coding)键值编码,单看这个名字可能不太好理解.其实翻译一下就很简单了,就是指iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值.而不需 ...
- Android开发技巧——大图裁剪
本篇内容是接上篇<Android开发技巧--定制仿微信图片裁剪控件> 的,先简单介绍对上篇所封装的裁剪控件的使用,再详细说明如何使用它进行大图裁剪,包括对旋转图片的裁剪. 裁剪控件的简单使 ...
- [开发技巧]·Numpy广播机制的深入理解与应用
[开发技巧]·Numpy广播机制的深入理解与应用 1.问题描述 我们在使用Numpy进行数据的处理时,经常会用到广播机制来简化操作,例如在所有元素都加上一个数,或者在某些纬度上作相同的操作.广播机制很 ...
- ES6 Javascript 实用开发技巧
ES6 实用开发技巧 定义变量/常量 ES6 中新增加了 let 和 const 两个命令,let 用于定义变量,const 用于定义常量 两个命令与原有的 var 命令所不同的地方在于,let, c ...
- [开发技巧]·TensorFlow&Keras GPU使用技巧
[开发技巧]·TensorFlow&Keras GPU使用技巧 1.问题描述 在使用TensorFlow&Keras通过GPU进行加速训练时,有时在训练一个任务的时候需要去测试结果 ...
- 你不知道的前端SDK开发技巧
最近在做公司内部的一个的一个SDK的重构,这里总结一些经验分享给大家. 类型检查和智能提示 作为一个SDK,我们的目标是让使用者能够减少查看文档的时间,所以我们需要提供一些类型的检查和智能提示,一般我 ...
- DelphiXE2 DataSnap开发技巧收集
DelphiXE2 DataSnap开发技巧收集 作者: 2012-08-07 09:12:52 分类:Delphi 标签: 作为DelphiXE2 DataSnap开发的私家锦囊, ...
随机推荐
- linux文档权限
1.登录 root 用户:su - mac一开始进入创建的用户是具有管理员权限的用户,但是密码却不是进入 root 用户的密码,可以使用 sudo su - 免密进入 root 用户. 2.退出 ro ...
- 主表a主表b 从表c中有ab两个表中各一个字段a1,b1 从表d中有ab两个表中各一个字段a2,b2
a1和a2在a表中具有唯一性 b1和b2在b表中具有唯一性 现在需要连接c表和d表 需要分两步来做 1.先让c表join表a和表b select c.*,a.a2,b.b2 from c inner ...
- [bzoj3274]Circle
https://www.zybuluo.com/ysner/note/1243396 题面 有\(n\)个排成一圈的格子,并且已知正整数\(k\)和\(m\),你需要往每个格子中填入一个大于等于\(k ...
- go 简单路由实现
一.golang 路由实现的简单思路 1.http启动后,请求路径时走统一的入口函数 1.通过统一函数入口,获取request 的url路径 2.通过对url的路径分析,确定具体执行什么函数 二.统一 ...
- 前端性能优化---减少http请求数量和减少请求资源的大小
减少http请求数量:就是资源的合并 减少http请求大小:就是资源的压缩 一.资源合并的原理: 资源不合并的缺点: 1.文件和文件之间有插入请求----请求a.js,b.js,c.js(三行 ...
- EF在应用程序配置文件中找不到名为“XXX”的连接字符串。
现象: 在配置EF的时候需要如题所述的问题,仔细检查了在EF实体模型对应程序集下的APP.Config文件中的ConnectionString配置项有了XXX项的数据库字符串的配置: <conn ...
- enc28j60网卡驱动模块添加进linux内核,Kconfig,Makefile配置过程
这里是要把http://www.cnblogs.com/hackfun/p/6260396.html中的enc28j60网卡驱动模块,添加到2.6.22.6内核中,这个模块代码不需要任何修改.只需要在 ...
- T-SQL语句以及几个数据库引擎
创建表 注意事项: A.自增长 B.数据库引擎, ISAM 是一个定义明确且历经时间考验的数据表格管理方法,它在设计之时就考虑到数据库被查询的次数要远大于更新的次数.因此,IS ...
- mysql下载和安装Windows服务
一.下载mysql:https://dev.mysql.com/downloads/mysql/,解压拷贝到D:\software\mysql-8.0.13-winx64 二.在D:\software ...
- php入门学习笔记
学习笔记[6.5-6.13] 1.常用命令 打开数据库格式: mysql -h主机地址 -u用户名 -p 重启nginx:sudo /etc/init.d/nginx restart或者service ...