事务是确保数据库一致的一种机制,是多条 SQL 语句组成的一系列的数据库操作,如果所有的 SQL 语句都操作成功,则认为事务成功,事务会被提交,其修改的数据就会生效。如果在事务中的 SQL 语句有一条或者多条操作失败,则事务不会成功,数据库中的数据将会被回滚到事务开始之前的状态,该事务中所有操作都会被取消。
事务功能是企业级数据库的一个重要部分,因为很多业务过程都包括多个步骤,并不是简单的操作一个数据表就能完成的。比如要在人员管理系统中删除一个人员,既要删除人员的基本资料,还要删除所有与该员工有关的信息,如邮件、文章等等,这一系列的数据库操作就构成了一个事务。
注意:在 MySQL 数据库中,只有使用了 Innodb 数据库引擎的数据库或表才支持事务,更多详细的介绍可以查看《MySQL事务》。
PHP 中想要使用事务有两种方式,一是使用 mysqli_begin_transaction()、mysqli_commit()、mysqli_rollback() 等函数来启动、提交或回滚一个事务;再者就是使用 mysqli_autocommit() 函数来关闭 MySQL 事务的自动提交模式。下面我们先来介绍以下这几个函数。
mysqli_begin_transaction() 函数可以启动一个事务,其语法格式如下:
面向对象风格的写法:
面向过程风格的写法:
参数说明如下:
mysqli_commit() 函数可以提交一个事务,其语法格式如下:
面向对象风格的写法:
面向过程风格的写法:
其中 $link 为使用 mysqli_connect() 函数创建的数据库连接。
mysqli_rollback() 函数可以回退当前事务,其语法格式如下:
面向对象风格的写法:
面向过程风格的写法:
其中 $link 为使用 mysqli_connect() 函数创建的数据库连接。
mysqli_autocommit() 函数可以打开或关闭本次数据库连接的自动提交事务模式,其语法格式如下:
面向对象风格的写法:
面向过程风格的写法:
其中 $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() 函数实现的话与上面的代码基本相同,只需要将上面代码的第七行更改为下面的样子即可: