PDO::beginTransaction() 方法的作用是启动一个事务;当事务中的所有 SQL 语句全部执行成功后,可以使用 PDO::commit() 方法来结束并提交一个事务;如果事务中某个 SQL 语句执行失败了,那么可以使用 PDO::rollBack() 方法来结束并回滚事务,事务中的所有 SQL 语句都将无效。注意,事务中的 SQL 语句要么全部成功执行,要么根本就不执行。
事务通常是通过把一批要执行的 SQL 语句“积蓄”起来,然后使之同时生效而,这样做的好处就是可以大大地提高这些 SQL 语句的执行的效率。换句话说,事务可以使脚本更快,而且更加健壮。
需要注意的是,并非每种数据库都支持事务,因此当第一次打开连接时,PDO 需要在“自动提交”模式下运行。自动提交模式意味着,如果数据库支持,运行的每个查询都有它自己的隐式事务,如果数据库不支持事务,则没有。
提示:PDO 仅在驱动层检查是否具有事务处理能力。如果某些运行时条件意味着事务不可用,且数据库服务接受请求去启动一个事务,PDO::beginTransaction() 将仍然返回 TRUE 而且没有错误。
当脚本结束或连接即将被关闭时,如果尚有未完成的事务,那么 PDO 将自动回滚这个事务。这种安全措施有可以避免在脚本意外终止时出现数据不一致的情况。也就是说,如果没有显式地提交事务,那么当某个地方出错时,将执行回滚来保证数据安全。
下面通过一个简单示例来演示以下 PDO 中事务的使用。假设有 userA 和 userB 两个银行账户,现在使用 userA 账户向 userB 账号中转账,使用事务来保证 userA 账户中转出一定金额的同时,userB 账户中转入相等的金额。
存放 userA 和 userB 两个账户的数据表的表结构如下所示:
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);
具体的实现代码如下所示:
<?php $dsn = "mysql:dbname=testdb;host=localhost"; $user = "root"; $password = "root"; $dbh = new PDO($dsn, $user, $password); //使用事务之前,要先关闭自动提交。不关闭的话,出现异常的时候没法回滚。 //据手册描述,ATTR_AUTOCOMMIT 属性只在 mysql、OCI(oracle)、firebird 三种数据库中可用 $dbh->setAttribute(PDO::ATTR_AUTOCOMMIT, 0); $price = 996; try { $dbh->beginTransaction(); //用户A账户扣除指定的金额 $sqlcmd = "UPDATE account SET cash=cash-$price WHERE name='userA'"; $affected_rows = $dbh->exec($sqlcmd); if ($affected_rows > 0) { echo "用户A账户扣除成功" . "<br>"; } else { throw new Exception("用户A账户扣除失败"); } //用户B账户增加指定的金额 $affected_rows = $dbh->exec("UPDATE account SET cash=cash+$price WHERE name='userB'"); if ($affected_rows > 0) { echo "用户B账户增加成功" . "<br>"; } else { throw new Exception("用户B账户增加失败"); } echo "转账成功"; //若前面两个步骤都成功,则提交事务 $dbh->commit(); }catch (PDOException $e) //若前面两个步骤中出现了异常,则回滚 { echo $e->getMessage(); $dbh->rollback(); } //对事务的使用结束之后,重新开启自动提交 $dbh->setAttribute(PDO::ATTR_AUTOCOMMIT, 1); ?>
原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/24060.html