yii mysql 事务处理_Yii2中事务的使用实例代码详解
前言
一般我们做业务逻辑,都不会仅仅关联一个数据表,所以,会面临事务问题。
数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。事务是数据库运行中的一个逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理。
准备
数据库引擎为innodb
本文使用的yii版本为2.0.5,只要是2.0以上就没有问题
运行环境为PHP7.0.0,Mysql5.6
Yii中的事务
处理异常
/**
* 测试事务
*/
public function actionTest(){
//创建事务
$tr = Yii::$app->db->beginTransaction();
try {
for($i=1;$i<=3;$i++){
$test = new Areas();
$test->name = 'name'.$i;
$test->sort=1;
if($test->save()){
echo "save $i | ";
}
}
$test = new Areas();
$test->name = 'ab'.$i;
$test->sorta=1; //写入不存在的字段
if(!$test->save()){
"save fail"; //如果没有写入就输出
}
//提交
$tr->commit();
} catch (Exception $e) {
//回滚
$tr->rollBack();
echo "rollback";
}
}
运行结果
save 1 | save 2 | save 3 | rollback
注意,因为最后的数据没有插入成功,触发了事务的回滚,所以数据表没有新增数据产生。
触发事务回滚的原因是代码出现了异常(Exception)。
处理数据失败
一般来讲,我们的运行中的代码是不会出现这种明显的异常,这种异常会在开发测试过程中消灭掉。
而真正造成数据需要回滚的是我们的某个业务出现问题,导致没有写入部分的数据。
/**
* 测试事务
*/
public function actionTest(){
//创建事务
$tr = Yii::$app->db->beginTransaction();
try {
for($i=1;$i<=3;$i++){
$test = new Areas();
$test->name = 'name'.$i;
$test->sort=1;
if($test->save()){
echo "save $i | ";
}
}
$test = new Areas();
$test->name = null; //数据库设计name不能为空,人为造成写入失败。
$test->sort=1; //写入不存在的字段
if(!$test->save()){
echo "save fail"; //如果没有写入就输出
}
//提交
$tr->commit();
} catch (Exception $e) {
//回滚
$tr->rollBack();
echo "rollback";
}
}
运行结果如下,数据库插入了三条数据。
save 1 | save 2 | save 3 | save fail
也就是说,如果因为业务逻辑导致某个数据表没有写入数据,也没有出现对应的回滚。
改进方案如下
/**
* 测试事务
*/
public function actionTest(){
//创建事务
$tr = Yii::$app->db->beginTransaction();
try {
for($i=1;$i<=3;$i++){
$test = new Areas();
$test->name = 'name'.$i;
$test->sort=1;
if($test->save()){
echo "save $i | ";
}
}
$test = new Areas();
$test->name = null; //数据库设计name不能为空,人为造成写入失败。
$test->sort=1; //写入不存在的字段
if(!$test->save()){
throw new \yii\db\Exception(); //手动抛出异常,再由下面捕获。
}
//提交
$tr->commit();
} catch (Exception $e) {
//回滚
$tr->rollBack();
echo "rollback";
}
}
运行结果如下,数据库没有插入新数据,事务被回滚。
save 1 | save 2 | save 3 | rollback
分散的数据处理
由于实际项目的复杂程度,导致我们的数据库操作分散在不同的Model中。
所以,实际项目的代码不会是上面的样子。
模拟需求
接收参数:
名字
性别
签名
业务处理流程:
接收参数
由发号器得到用户的uid,发号器对应数据表增加一位数字
把名字、性别、签名和上一步的uid写入用户信息表
初始化用户余额表
回滚触发时机:
初始化余额表没有传入uid导出没有写入数据
实际代码
//Controller
/**
* 测试事务-注册用户
*/
public function actionReg()
{
//获取请求
$request = Yii::$app->request;
//设定返回格式
$response = Yii::$app->response;
$response->format = \yii\web\Response::FORMAT_JSON; //返回json
//测试代码,去掉验证身份步骤
$name = $request->get("name");
$gender = $request->get("gender");
$sign = $request->get("sign");
//测试代码,省略参数校验步骤
$tr = Yii::$app->db->beginTransaction();
try {
//得到uid
$uid = App::getSeNo();
UserProfile::add($uid, $name, $gender, 1, $sign);
$user_balance = UserBalance::initUserBalance($uid);
$tr->commit(); //提交数据
} catch (Exception $e) {
//回滚
$tr->rollBack();
return $e->getMessage(); //返回自定义异常信息
}
return $user_balance;
}
//UserProfile
/**
* 添加用户信息
* @param $user_id
* @param $nikename
* @param $gender
* @param $user_type
* @param string $intro
* @return UserProfile
* @throws \Exception
*/
public static function add($user_id, $nikename, $gender,$user_type,$intro="") {
$model = new UserProfile();
$model->gender = $gender;
$model->nikename = $nikename;
$model->user_id = $user_id;
$model->user_type=$user_type;
$model->intro=$intro;
$model->update_time = time();
$insert =$model->insert();
if(!$insert){
throw new Exception("没有写入用户资料");
}
return $model;
}
//UserBalance
/**
* 初始化用户的可提现余额
* @param $user_id
*/
public static function initUserBalance($user_id){
$info=self::find()->where(['user_id'=>$user_id])->one();
if(!$info ){
$model=new UserBalance();
$model->user_id = $user_id;
$model->price= "0";
$model->update_time=time();
$insert = $model->insert();
if(!$insert){
throw new Exception("没有初始化用户余额");
}
$info=$model;
}
return $info->attributes;
}
正常的结果如下
{"id":124,"user_id":1473179883,"price":"0","update_time":1473179883}
如果把初始化用户余额部分的user_id没有传递成功,返回的结果如下
"没有初始化用户余额"
我们可以针对具体情况定位到错误所在位置,及时修改。
事务(Transaction)
从上面的实际代码可以看出,创建了事务,只要在范围内,就算是引入的别的Model也能把异常NG返回,完成回滚操作。
一般情况下,整个Yii应用使用了同一个数据库连接,或者说是使用了单例。
而在yii\db\Connection中,又对事务对象进行了缓存:
class Connection extends Component
{
// 保存当前连接的有效Transaction对象
private $_transaction;
// 已经缓存有事务对象,且事务对象有效,则返回该事务对象
// 否则返回null
public function getTransaction()
{
return $this->_transaction && $this->_transaction->getIsActive() ? $this->_transaction : null;
}
// 看看启用事务时,是如何使用事务对象的
public function beginTransaction($isolationLevel = null)
{
$this->open();
// 缓存的事务对象有效,则使用缓存中的事务对象
// 否则创建一个新的事务对象
if (($transaction = $this->getTransaction()) === null) {
$transaction = $this->_transaction = new Transaction(['db' => $this]);
}
$transaction->begin($isolationLevel);
return $transaction;
}
}
因此,可以认为整个Yii应用,使用了同一个 Transaction 对象,也就是说, Transaction::_level 在整个应用的生命周期中,是有延续性的。 这是实现事务嵌套的关键和前提。
以上所述是小编给大家介绍的Yii2中事务的使用实例代码详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!
yii mysql 事务处理_Yii2中事务的使用实例代码详解相关推荐
- vue build text html,Vue中v-text / v-HTML使用实例代码详解_放手_前端开发者
废话少说,代码如下所述: /p> 显示123 /p> 补充:vuejs {{}},v-text 和 v-html的区别 {{message}} let app = new Vue({ el ...
- python输出变量代码_Python中变量的输入输出实例代码详解
1.变量的输入: input函数: input() input("请输入银行卡密码") password = input("请输入银行卡密码") 变量名 = i ...
- python的常量和变量_python中的常量和变量代码详解
局部和全局变量: # name='lhf' # def change_name(): # # global name # name='帅了一比' # print('change_name',name) ...
- java迭代器删除元素_java迭代器中删除元素的实例操作详解
java迭代器中删除元素的实例操作详解 2021-01-21 16:40:08 我们知道通过Iterator,可以对集合中的元素进行遍历.那么在其中遇到我们不需要的元素时,可不可以在遍历的时候顺便给删 ...
- vue中 点击事件的写法_vue实现绑定事件的方法实例代码详解
一.前言 vuejs中的事件绑定,使用来完成的,这里函数名是定义在Vue实例中的methods对象中的,Vue实例可以直接访问其中的方法. 二.事件绑定方式 1. 直接在标签中写js方法 执行方法的第 ...
- MySQL中事务四大特性的实现详解
MySQL事务的四大特性的实现 基本概念 原子性实现 隔离性实现 已提交读 可重复读 持久性实现 日志文件刷新策略 基本概念 事务的四大特性ACID : 原子性Atomic : 事务的所有的SQL操作 ...
- MySQL存储引擎中的MyISAM和InnoDB区别详解
MyISAM是MySQL的默认数据库引擎(5.5版之前),由早期的ISAM(Indexed Sequential Access Method:有索引的顺序访问方法)所改良.虽然性能极佳,但却有一个缺点 ...
- android studio table居中代码_五个方法实例代码详解教你在CSS中实现垂直居中
点击上面"蓝字"关注我们 你是否和小编一样在编辑一个版面时,通常用到水平居中和垂直居中,而水平居中很好处理,不外乎就是设定margin:0 auto;或是text-align:ce ...
- php 变量代码,php中的可变变量(代码详解)
php中的可变变量 有时候使用可变变量名是很方便的.就是说,一个变量的变量名可以动态的设置和使用.一个普通的变量通过声明来设置,例如:<?php $a = 'hello'; ?> 一个可变 ...
最新文章
- 磁盘空间神秘消失事件
- 速神经网络的训练算法LARS/LAMB工作原理 --UC Berkeley在读博士生尤洋
- Java 洛谷 P1200 [USACO1.1]你的飞碟在这儿 Your Ride Is Here
- mybatis实现增删改查xml配置和后端Java编程完整教程
- JavaScript 复习之 事件模型 和 Event对象
- Arch Linux 安装总结
- Python中的一些特殊函数
- Bootstrap3 表单控件的状态
- Windows 怎么了?微软又停止一大版本更新
- SID与域信任不一致导致AD无法登陆/server2003系统封装
- 100本Python机器学习、深度学习电子书,免费送!
- java给出汉字“你”“我”“他”在Unicode表中的位置
- 网课查课插件 支持 60类型+ 彩虹查课插件 网络查课查询
- 高项论文(沟通管理)
- OpenCV怎么下载?OpenCV下载后怎么配置?
- 2750 心系南方灾区
- 抢红包算法 c++_“抠抠族”的出行利器,斤斤计较的几何C为了节能果然够拼
- 硬件-4-戴尔Inspiron 5577笔记本拆机
- 2018 世界杯:科技辅助裁判是否靠谱?
- 漫画图解 ElasticSearch 搜索原理
热门文章
- 发现了阿里云 APP 的一个小 BUG
- 西湖大学鞠峰组:环境宏病毒组学分析思路与常用工具
- NBT:牛瘤胃微生物组的参考基因组集
- 水稻微生物组时间序列分析2b-散点图拟合
- Nature Reviews:拥抱未知:解析土壤微生物组的复杂性
- oracle自动分区maxvalue,分区表中的maxvalue参数设置-Oracle
- R语言ggplot2可视化:ggplot2可视化时间序列数据并在末尾数据点添加数值标签(number label)
- Matplotlib使用scatter函数在Python中绘制气泡图(bubble plot)、通过size参数指定数据点的大小
- R语言广义加性模型GAMs:可视化每个变量的样条函数、样条函数与变量与目标变量之间的平滑曲线比较、并进行多变量的归一化比较、测试广义线性加性模型GAMs在测试集上的表现(防止过拟合)
- R语言诊断试验数据处理与ROC分析实战案例:联合诊断ROC