PHP MySQL事务处理

事务是确保数据库一致的一种机制,是多条 SQL 语句组成的一系列的数据库操作,如果所有的 SQL 语句都操作成功,则认为事务成功,事务会被提交,其修改的数据就会生效。如果在事务中的 SQL 语句有一条或者多条操作失败,则事务不会成功,数据库中的数据将会被回滚到事务开始之前的状态,该事务中所有操作都会被取消。

事务功能是企业级数据库的一个重要部分,因为很多业务过程都包括多个步骤,并不是简单的操作一个数据表就能完成的。比如要在人员管理系统中删除一个人员,既要删除人员的基本资料,还要删除所有与该员工有关的信息,如邮件、文章等等,这一系列的数据库操作就构成了一个事务。

注意:在 MySQL 数据库中,只有使用了 Innodb 数据库引擎的数据库或表才支持事务,更多详细的介绍可以查看《MySQL事务》。

PHP 中想要使用事务有两种方式,一是使用 mysqli_begin_transaction()、mysqli_commit()、mysqli_rollback() 等函数来启动、提交或回滚一个事务;再者就是使用 mysqli_autocommit() 函数来关闭 MySQL 事务的自动提交模式。下面我们先来介绍以下这几个函数。

1) begin_transaction()

mysqli_begin_transaction() 函数可以启动一个事务,其语法格式如下:

面向对象风格的写法:

mysqli::begin_transaction([int $flags = 0[, string $name]])

面向过程风格的写法:

mysqli_begin_transaction(mysqli $link[, int $flags = 0[, string $name]])

参数说明如下:

  • $link:面向过程风格的写法中,表示由 mysql_connect() 函数创建的数据库连接;
  • $flags:可选参数,可以是以下所示的值:

    • MYSQLI_TRANS_START_READ_ONLY:以只读模式启动事务,需要 MySQL5.6 及以上的版本;
    • MYSQLI_TRANS_START_READ_WRITE:以读写模式启动事务,需要 MySQL5.6 及以上的版本;
    • MYSQLI_TRANS_START_WITH_CONSISTENT_SNAPSHOT:使用一致快照模式启动事务。
  • $name:可选参数,用来设置事务的保存点名称。

2) mysqli_commit()

mysqli_commit() 函数可以提交一个事务,其语法格式如下:

面向对象风格的写法:

mysqli::commit()

面向过程风格的写法:

mysqli_commit(mysqli $link)

其中 $link 为使用 mysqli_connect() 函数创建的数据库连接。

3) mysqli_rollback()

mysqli_rollback() 函数可以回退当前事务,其语法格式如下:

面向对象风格的写法:

mysqli::rollback()

面向过程风格的写法:

mysqli_rollback(mysqli $link)

其中 $link 为使用 mysqli_connect() 函数创建的数据库连接。

4) mysqli_autocommit()

mysqli_autocommit() 函数可以打开或关闭本次数据库连接的自动提交事务模式,其语法格式如下:

面向对象风格的写法:

mysqli::autocommit(bool $mode)

面向过程风格的写法:

mysqli_autocommit(mysqli $link, bool $mode)

其中 $link 为使用 mysqli_connect() 函数创建的数据库连接,$mode 用来设置是否打开自动提交模式。

了解了这几个函数的语法后,下面通过示例程序来演示事务的使用。

【示例】假设有 userA 和 userB 两个账户,然后使用 userA 账户向 userB 账号中转账,使用事务来保证 userA 账户中减去一定金额的同时,userB 账户中得到相等的金额。首先需要在数据库中创建一个 InnoDB 类型的数据表 accoubnt,并创建上面的两个账户的信息,如下所示:

DROP TABLE IF EXISTS `account`;
CREATE TABLE `account`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `name` varchar(45) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL COMMENT '用户名',
  `cash` decimal(9, 2) NOT NULL COMMENT '账户余额',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;

INSERT INTO `account` VALUES (1, 'userA', 100000.00);
INSERT INTO `account` VALUES (2, 'userB', 90000.00);

使用 mysqli_begin_transaction()、mysqli_commit()、mysqli_rollback() 等函数的实现代码如下所示:

<?php
    $link = new mysqli('127.0.0.1', 'root', 'root', 'testdb'); // 连接数据库
    if(mysqli_connect_errno()){                                // 检查连接错误
        printf("连接失败:%s<br>", mysqli_connect_error());
        exit();
    }
    $link -> begin_transaction();                              // 开始事务
    $success = true;                                           // 设置事务状态
    $price = 999;                                              // 转账金额
    $sql1 = "UPDATE account SET cash=cash-$price WHERE name='userA'"; // 从 userA 账户转出的 SQL 语句
    $result = $link -> query($sql1);                           // 执行SQL语句
    if(!$result || $link->affected_rows != 1){                 // 如果执行失败则修改事务状态
        $success = false;
    }
    $sql2 = "UPDATE account SET cash=cash+$price WHERE name='userB'"; // 向 userB 账户中转入的 SQL 语句
    $res = $link -> query($sql2);                              // 执行SQL语句
    if(!$res || $link->affected_rows != 1){                    // 如果执行失败则修改事务状态
        $success = false;
    }
    if($success){                                              // 根据事务状态选择提交或者回滚事务
        $link->commit();
        echo '转账成功!';
    }else{
        $link->rollback();
        echo '转账失败!';
    }
    $link->close();
?>

使用 mysqli_autocommit() 函数实现的话与上面的代码基本相同,只需要将上面代码的第七行更改为下面的样子即可:

$link -> autocommit(0);

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/24022.html

(0)
上一篇 2021年7月20日 11:30
下一篇 2021年7月20日 11:31

相关推荐

发表回复

登录后才能评论