今天看啥  ›  专栏  ›  王佳斌

Thinkphp 6 - 事务操作(自动(transaction) / 手动(startTrans))

王佳斌  · CSDN  ·  · 2020-08-29 17:15

前言

Mysql 事务详细描述: https://www.runoob.com/mysql/mysql-transaction.html

要想了解 TP6 事务操作,首先要知道什么是事务(即数据库事务)。


😃 举个例子,我们去银行转账,操作可以分为下面两个环节:

  1. 从第一个账户划出款项。
  2. 将款项存入第二个账户。

在这个过程中,两个环节是 关联 的。第一个账户划出款项必须保证正确的存入第二个账户,如果第二个环节没有完成,整个的过程都应该取消,否则就会发生丢失款项的问题。

整个交易过程,可以看作是一个事务, 成功则全部成功,失败则需要全部撤消 ,这样可以避免当操作的中间环节出现问题时,产生数据不一致的问题。

数据库事务是一个逻辑上的划分,有的时候并不是很明显,它可以是一个操作步骤也可以是多个操作步骤。我们可以这样理解数据库事物:对数据库所做的一系列修改,在修改过程中,暂时不写入数据库,而是缓存起来,用户在自己的终端可以预览变化,直到全部修改完成,并经过检查确认无误后,一次性提交并写入数据库,在提交之前,必要的话所做的修改都可以取消。提交之后,就不能撤销,提交成功后其他用户才可以通过查询浏览数据的变化。

一、创建数据库表

我们先来创建一个表来模拟一下场景(用于后续代码演示),具体情况如图所示:
在这里插入图片描述

二、配置数据库

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,
    ],
    
],
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

三、更改数据库引擎

TP6 中使用事务处理的话,需要数据库引擎支持事务处理,拿 Mysql 举例,你需要将默认的数据库引擎改为 InnoDB 引擎才能使用。

哪个数据库表需要事务操作,就更改哪个表的数据库引擎。

【数据库表上右键】→【设计表】→【选项】→【引擎】→【InnoDB】

在这里插入图片描述

三、事务操作

官方文档: https://www.kancloud.cn/manual/thinkphp6_0/1037573

TP6 提供了 3 种事务操作 API:

  1. 自动处理:transaction
  2. 手动处理:startTrans
  3. 分布式事务:本篇不谈

第一种,自动处理。

使用 transaction 方法操作数据库事务,当闭包中的代码发生异常会自动回滚,这种方法说白了就是让 TP6 自动处理:

// 创建一个控制器来测试

<?php

namespace app\controller;
use think\facade\Db;

class Index
{

    /**
     * 事务: 马云转账给李嘉诚50元
     *
     * @return void
     */
    public function index()
    {

        /**
         * 事务处理类(transaction)-【自动】
         * @闭包中代码发生异常后自动回滚
         * 
         * ------------ 假设条件 ----------------
         * @当执行语句马云账户-50后
         * @李嘉诚+50那句代码因各种原因导致执行失败后
         * 
         * ------------ 最终结果 ----------------
         * @马云的账户不会-50(因为回滚了)
         * @李嘉诚更不会加(因为没执行)
         */
        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')]);
            
        });
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

在这里插入图片描述


第二种,手动处理。

使用 startTrans | try | catch 方法处理数据库事务,跟自动处理类似,只不过是手动控制提交和回滚,能执行其他业务逻辑代码。

手动 / 自动基本相同,这里不再解释。

<?php

namespace app\controller;
use think\facade\Db;

class Index
{

    /**
     * 事务: 马云转账给李嘉诚50元
     *
     * @return void
     */
    public function index()
    {
        
        /**
         * 事务处理类(startTrans)-【手动】
         */
        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();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

第三种。全局(分布式)事务。

主要是进行处理 跨库事务 ,即 多个数据库进行事务交互

由于篇幅太长了,本文不继续写了,详细看文档,也很简单。

官方文档: https://www.kancloud.cn/manual/thinkphp6_0/1037573




原文地址:访问原文地址
快照地址: 访问文章快照