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开发的私家锦囊, ...
随机推荐
- Intellij IDEA报错:Could not save application settings: java.io.IOException: java.lang.AssertionError: Unexpected content storage modificat
Question: i have a message saying "Could not save application settings: java.io.IOException: ja ...
- Meter Bus解析4:升压斩波电路
Meter Bus解析1(http://blog.csdn.net/qingwufeiyang12346/article/details/47767595),对Meter Bus进行 ...
- 【Aladdin Unity3D Shader编程】之四 贴图纹理
关于纹理贴图介绍 纹理坐标也叫UV坐标,UV坐标都是0~1,并不是我们所理解的像素坐标,相当于是一个百分比. 编写shader映射纹理 将纹理的颜色取代漫反射的颜色 Shader "Alad ...
- 继承自TWinControl的控件不能在设计期间接受子控件,用代码设置子控件却可以(它的自绘是直接改写PaintWindow虚函数,而不是覆盖Paint函数——对TWinControl.WMPaint又有新解了)
这个控件直接继承自TWinControl,因此不是改写Paint;函数,而是直接改写PaintWindow虚函数,它在VCL框架里被直接调用,直接就把自己画好了(不用走给控件Perform(WM_Pa ...
- JPush 初始化失败,直接按照官方文档的格式写的,portal上的包名肯定不会错,mainfest里面直接指定${applicationId}
错误日志: 11-27 09:59:19.670 26124-26124/? D/dalvikvm: Late-enabling CheckJNI 11-27 09:59:20.008 26124-2 ...
- Vue相关开源项目库汇总 http://www.opendigg.com/tags/front-vue
awesome-github-vue 是由OpenDigg整理并维护的Vue相关开源项目库集合.我们会定期同步OpenDigg上的项目到这里,也欢迎各位提交项目给我们. 如果收录的项目有错误,可以通过 ...
- bzoj1098
并查集+dfs 先开始想和不相连的点用并查集连起来,最后看每个连通块有多少个点就行了,但是这样是O(n*n)的,然而我并没有想到补图 其实就是求补图有多少连通块,因为补图中两个点有边,那么这两个点必须 ...
- Python3基础复习
目录 基本语法 运算符 输出格式 数据类型 数据结构 函数 面向对象 补充 异常 模块和包 文件 时间 线程和进程 基本语法 基本语法只列举与Java不一样的. 运算符 and, or而非 & ...
- 使用centos 5.x 64位系统安装astgo 2014 v7.3教程(含全套安装文件)
版本特色: 全自动安装 安装过程中不用频繁输入yes或回车 自带完整号码归属地数据库 自带触屏版WAP ·首先确定你需要使用astgo 2014 7.0还是7.3: astgo 2014 v 7.0 ...
- js返回上一层
Javascript 返回上一页 1. Javascript 返回上一页 history.go(-1), 返回两个页面: history.go(-2); 2. history.back(). wind ...