Laravel如何使用数据库事务及捕获事务失败后的异常详解


Posted in PHP onOctober 23, 2017

前言

如果大家在Laravel中要想在数据库事务中运行一组操作,则可以在 DB facade 中使用 transaction 方法。如果在事务的闭包内抛出异常,事务将会被自动还原。如果闭包运行成功,事务将被自动提交。

你不需要担心在使用 transaction 方法时还需要亲自去手动还原或提交事务:

DB::transaction(function () {
 DB::table('users')->update(['votes' => 1]);

 DB::table('posts')->delete();
});

手动操作事务

如果你想手动处理事务并对还原或提交操作进行完全控制,则可以在 DB facade 使用 beginTransaction 方法:

DB::beginTransaction();

你也可以通过 rollBack 方法来还原事务:

DB::rollBack();

最后,可以通过 commit 方法来提交这个事务:

DB::commit();

注意: DB facade 的事务方法也可以用来控制 查询语句构造器 及 Eloquent ORM 的事务。

示例介绍

假设有要在数据库中存储一个知识点,这个知识点同时属于两个不同的考点,也就是考点和知识点这两个数据是多对多的关系,那么要实现这种数据结构就需要三个表:

知识点表 wiki:

---------------------------------------
id  title    content
---------------------------------------

考点表 tag:

-------------------
id  name
-------------------

考点知识点关联表 wiki_tag_rel

----------------------------------
id   tag_id  wiki_id
----------------------------------

现在要开启事务新增Wiki数据,新增wiki成功后再把它关联到指定的考点上去

(在laravel中使用查询构建器或者Eloquent ORM执行query时,如果失败会返回 Illuminate\Database\QueryException 异常)

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Database\QueryException;
use App\Wiki;

class TestController extends Controller
{
 //用DB facade的事务方法控制 查询语句构建器的事务
 public function storeWiki(Request $request)
 {
  DB::beginTransaction();
  try {
   $tagIds = explode(',', $request->get('tag_id'));
   $wiki_id = DB::table('wiki')->insertGetId([
    'title' => $request->get('title'),
    'content' => $request->get('content')
   ]);

   $relationData = [];
   foreach($tagIds as $tagId) {
    $data = ['wiki_id' => $wiki_id, 'tag_id' => $tagId];
    $relationData[] = $data;
   }
   DB::table('wiki_tag_rel')->insert($relationData);
   DB::commit();
  } catch(\Illuminate\Database\QueryException $ex) {
   DB::rollback();
   return \Response::json(['status' => 'error', 'error_msg' => 'Failed, please contact supervisor']);
  }
  
  return \Response::json(['status' => 'ok']);
 }


 //用DB facade的事务方法控制 Eloquent ORM的事务
 public function createWiki(array $data)
 {
  DB::beginTransaction();
  try {
   $tagIds = explode(',', $data['tag_id']);
   $newWiki = Wiki::create([
    'title' => $data['title'],
    'content' => $data['content']
   ]);
   //Wiki和Tag两个Model使用了belongsToMany建立了多对多的关系
   //通过attach方法来附加wiki和tag的关系(写入中间表)
   $newWiki->tags()->attach($tagIds);
   DB::commit();
  } catch(QueryException $ex) {
   DB::rollback();
   return \Response::json(['status' => 'error', 'error_msg' => 'Failed, please contact supervisor']);
  }

  return \Response::json(['status' => 'ok']);
  }

}

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

PHP 相关文章推荐
基于mysql的bbs设计(二)
Oct 09 PHP
PHP4和PHP5共存于一系统
Nov 17 PHP
php读取文件内容至字符串中,同时去除换行、空行、行首行尾空格(Zjmainstay原创)
Jul 31 PHP
php一些错误处理的方法与技巧总结
Aug 10 PHP
php递归使用示例(php递归函数)
Feb 14 PHP
phpMyAdmin安装并配置允许空密码登录
Jul 04 PHP
Yii使用DeleteAll连表删除出现报错问题的解决方法
Jul 14 PHP
PHP 7.1新特性的汇总介绍
Dec 16 PHP
php实现36进制与10进制转换功能示例
Jan 10 PHP
PHP实现动态获取函数参数的方法示例
Apr 02 PHP
PHP token验证生成原理实例分析
Jun 05 PHP
微信公众号之主动给用户发送消息功能
Jun 22 PHP
PHP实现实时生成并下载超大数据量的EXCEL文件详解
Oct 23 #PHP
Laravel学习教程之model validation的使用示例
Oct 23 #PHP
laravel实现批量更新多条记录的方法示例
Oct 22 #PHP
利用PHP获取汉字首字母并且分组排序详解
Oct 22 #PHP
Laravel 5.4因特殊字段太长导致migrations报错的解决
Oct 22 #PHP
PHP高效获取远程图片尺寸和大小的实现方法
Oct 20 #PHP
PHP静态延迟绑定和普通静态效率的对比
Oct 20 #PHP
You might like
CI框架整合smarty步骤详解
2016/05/19 PHP
PHP基于ORM方式操作MySQL数据库实例
2017/06/21 PHP
JavaScript 对象的属性和方法4种不同的类型
2010/03/19 Javascript
jQuery的text()方法用法分析
2014/12/20 Javascript
moment.js轻松实现获取当前日期是当年的第几周
2015/02/05 Javascript
Javascript中的包装类型介绍
2015/04/02 Javascript
EasyUi中的Combogrid 实现分页和动态搜索远程数据
2016/04/01 Javascript
jQuery height()、innerHeight()、outerHeight()函数的区别详解
2016/05/23 Javascript
JS实现n秒后自动跳转的两种方法
2020/11/30 Javascript
微信小程序 基础知识css样式media标签
2017/02/15 Javascript
微信小程序引用公共js里的方法的实例详解
2017/08/17 Javascript
webpack踩坑之路图片的路径与打包
2017/09/05 Javascript
node.js将MongoDB数据同步到MySQL的步骤
2017/12/10 Javascript
Angular学习笔记之集成三方UI框架、控件的示例
2018/03/23 Javascript
JS在if中的强制类型转换方式
2018/07/15 Javascript
Vue实现调节窗口大小时触发事件动态调节更新组件尺寸的方法
2018/09/15 Javascript
vue 配置多页面应用的示例代码
2018/10/22 Javascript
详解Vue-cli3 项目在安卓低版本系统和IE上白屏问题解决
2019/04/14 Javascript
layui表单提交到后台自动封装到实体类的方法
2019/09/12 Javascript
Vue使用Ref跨层级获取组件的步骤
2021/01/25 Vue.js
[48:28]完美世界DOTA2联赛循环赛FTD vs Magma第二场 10月30日
2020/10/31 DOTA
Python实现求笛卡尔乘积的方法
2017/09/16 Python
python hbase读取数据发送kafka的方法
2018/12/27 Python
对numpy下的轴交换transpose和swapaxes的示例解读
2019/06/26 Python
如何解决django-celery启动后迅速关闭
2019/10/16 Python
python元组和字典的内建函数实例详解
2019/10/22 Python
详解Python调用系统命令的六种方法
2021/01/28 Python
IE浏览器单独写CSS样式的几种方法
2014/10/14 HTML / CSS
大学生就业自我鉴定
2013/10/26 职场文书
室内设计专业个人的自我评价
2013/12/18 职场文书
三年大学自我鉴定
2014/01/16 职场文书
中餐厅经理岗位职责
2014/04/11 职场文书
弘扬民族精神演讲稿
2014/05/07 职场文书
英语系本科生求职信
2014/07/15 职场文书
介绍信范文
2015/01/31 职场文书
python数据库批量插入数据的实现(executemany的使用)
2021/04/30 Python