前言
Mysql
事务详细描述:https://www.runoob.com/mysql/mysql-transaction.html
要想了解 TP6
事务操作,首先要知道什么是事务(即数据库事务)。
举个例子,我们去银行转账,操作可以分为下面两个环节:
- 从第一个账户划出款项。
- 将款项存入第二个账户。
在这个过程中,两个环节是 关联 的。第一个账户划出款项必须保证正确的存入第二个账户,如果第二个环节没有完成,整个的过程都应该取消,否则就会发生丢失款项的问题。
整个交易过程,可以看作是一个事务,成功则全部成功,失败则需要全部撤消,这样可以避免当操作的中间环节出现问题时,产生数据不一致的问题。
数据库事务是一个逻辑上的划分,有的时候并不是很明显,它可以是一个操作步骤也可以是多个操作步骤。我们可以这样理解数据库事物:对数据库所做的一系列修改,在修改过程中,暂时不写入数据库,而是缓存起来,用户在自己的终端可以预览变化,直到全部修改完成,并经过检查确认无误后,一次性提交并写入数据库,在提交之前,必要的话所做的修改都可以取消。提交之后,就不能撤销,提交成功后其他用户才可以通过查询浏览数据的变化。
一、创建数据库表
我们先来创建一个表来模拟一下场景(用于后续代码演示),具体情况如图所示:
二、配置数据库
prefix
表前缀如果不配置,则无法使用name()
。
建好表后,在 config/database.php
配置一下,注意配置一下表前缀 tp6_
。
// 数据库连接配置信息
'connections' => [
'mysql' => [
// 数据库类型
'type' => 'mysql',
// 服务器地址
'hostname' => '127.0.0.1',
// 数据库名
'database' => 'demo',
// 用户名
'username' => 'root',
// 密码
'password' => 'root',
// 端口
'hostport' => '3306',
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => 'utf8',
// 数据库表前缀
'prefix' => 'tp6_',
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'deploy' => 0,
// 数据库读写是否分离 主从式有效
'rw_separate' => false,
// 读写分离后 主服务器数量
'master_num' => 1,
// 指定从服务器序号
'slave_no' => '',
// 是否严格检查字段是否存在
'fields_strict' => true,
// 是否需要断线重连
'break_reconnect' => false,
// 监听SQL
'trigger_sql' => env('app_debug', true),
// 开启字段缓存
'fields_cache' => false,
// 字段缓存路径
'schema_cache_path' => app()->getRuntimePath() . 'schema' . DIRECTORY_SEPARATOR,
],
],
三、更改数据库引擎
在 TP6
中使用事务处理的话,需要数据库引擎支持事务处理,拿 Mysql
举例,你需要将默认的数据库引擎改为 InnoDB
引擎才能使用。
哪个数据库表需要事务操作,就更改哪个表的数据库引擎。
【数据库表上右键】→【设计表】→【选项】→【引擎】→【InnoDB】
三、事务操作
官方文档:https://www.kancloud.cn/manual/thinkphp6_0/1037573
TP6
提供了 3 种事务操作 API:
- 自动处理:transaction
- 手动处理:startTrans
- 分布式事务:本篇不谈
第一种,自动处理。
使用 transaction
方法操作数据库事务,当闭包中的代码发生异常会自动回滚,这种方法说白了就是让 TP6
自动处理:
// 创建一个控制器来测试
<?php
namespace app\controller;
use think\facade\Db;
class Index
{
public function index()
{
Db::transaction(function(){
// 马云账户 -50
Db::name('user')//demo数据库tp6_user表
-> where('name', '马云')//条件(name="马云")
-> save(['money' => Db::raw('money - 50')]);//更新数据
// 李嘉诚账户 +50
Db::name('user')
-> where('name', '李嘉诚')
-> save(['money' => Db::raw('money + 50')]);
});
}
}
第二种,手动处理。
使用 startTrans | try | catch
方法处理数据库事务,跟自动处理类似,只不过是手动控制提交和回滚,能执行其他业务逻辑代码。
手动 / 自动基本相同,这里不再解释。
<?php
namespace app\controller;
use think\facade\Db;
class Index
{
public function index()
{
Db::startTrans();
try {
// 马云账户 -50
Db::name('user')
-> where('name', '马云')
-> save(['money' => Db::raw('money - 50')]);
// 李嘉诚账户 +50
Db::name('user')
-> where('name', '李嘉诚')
-> save(['money' => Db::raw('money + 50')]);
// 提交事务
Db::commit();
}
catch (\Exception $e) {##这里参数不能删除($e:错误信息)
// 做一些业务逻辑(包括反馈提示等)
// ...
// 回滚事务
Db::rollback();
}
}
}
第三种。全局(分布式)事务。
主要是进行处理 跨库事务,即 多个数据库进行事务交互。
由于篇幅太长了,本文不继续写了,详细看文档,也很简单。
官方文档:https://www.kancloud.cn/manual/thinkphp6_0/1037573