2024年PHP日本会议

事务和自动提交

现在您已通过PDO连接,在开始发出查询之前,您必须了解PDO如何管理事务。如果您以前从未遇到过事务,它们提供了4个主要特性:原子性、一致性、隔离性和持久性 (ACID)。简单来说,在事务中执行的任何工作,即使是分阶段执行的,也保证能够安全地应用于数据库,并且在提交时不会受到其他连接的干扰。事务性工作也可以根据您的请求自动撤销(前提是您尚未提交它),这使得脚本中的错误处理更容易。

事务通常通过“保存”要一次性应用的更改批次来实现;这具有显著提高这些更新效率的良好副作用。换句话说,事务可以使您的脚本更快,并可能更健壮(您仍然需要正确使用它们才能获得该好处)。

不幸的是,并非所有数据库都支持事务,因此当您第一次打开连接时,PDO需要以所谓的“自动提交”模式运行。自动提交模式意味着您运行的每个查询都有其自己的隐式事务(如果数据库支持),或者如果没有事务,则没有事务。如果您需要事务,则必须使用PDO::beginTransaction()方法来启动一个事务。如果底层驱动程序不支持事务,则会抛出PDOException(无论您的错误处理设置如何:这始终是严重错误情况)。一旦您处于事务中,您可以使用PDO::commit()PDO::rollBack()来结束它,具体取决于您在事务期间运行的代码是否成功。

警告

PDO仅在驱动程序级别检查事务功能。如果某些运行时条件意味着事务不可用,则如果数据库服务器接受启动事务的请求,PDO::beginTransaction() 仍将返回true而不会出错。

一个例子是在MySQL数据库上尝试对MyISAM表使用事务。

当脚本结束或连接即将关闭时,如果您有未完成的事务,PDO将自动回滚它。这是一项安全措施,有助于避免脚本意外终止时出现不一致的情况——如果您没有显式提交事务,则假定出现了一些问题,因此为了数据安全而执行回滚。

警告

只有通过PDO::beginTransaction()启动事务时,才会发生自动回滚。如果您手动发出启动事务的查询,PDO无法知道它,因此如果发生不好的事情,则无法回滚它。

示例 #1 在事务中执行批处理

在以下示例中,让我们假设我们正在为一个新员工创建一组条目,该员工已被分配了ID号23。除了输入该人的基本数据外,我们还需要记录他们的薪水。进行两次单独更新非常简单,但是通过将它们包含在PDO::beginTransaction()PDO::commit()调用中,我们保证在它们完成之前,没有人能够看到这些更改。如果出现问题,catch块会回滚自事务启动以来所做的所有更改,然后打印出错误消息。

<?php
try {
$dbh = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2',
array(
PDO::ATTR_PERSISTENT => true));
echo
"Connected\n";
} catch (
Exception $e) {
die(
"Unable to connect: " . $e->getMessage());
}

try {
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$dbh->beginTransaction();
$dbh->exec("insert into staff (id, first, last) values (23, 'Joe', 'Bloggs')");
$dbh->exec("insert into salarychange (id, amount, changedate)
values (23, 50000, NOW())"
);
$dbh->commit();

} catch (
Exception $e) {
$dbh->rollBack();
echo
"Failed: " . $e->getMessage();
}
?>

您不仅限于在事务中进行更新;您还可以发出复杂的查询来提取数据,并可能使用这些信息来构建更多更新和查询;在事务活动期间,您可以保证在您工作过程中没有人可以进行更改。有关事务的更多信息,请参阅您的数据库服务器提供的文档。

添加注释

用户贡献的注释 3条注释

6
hooby404 at gmail dot com
2年前
> 您不仅限于在事务中进行更新;您还可以发出复杂的
> 查询来提取数据,并可能使用这些信息来构建更多更新
> 和查询;在事务活动期间,您可以保证在您工作过程中没有人可以
> 进行更改。有关事务的更多信息,请参阅
关于事务的更多信息,请参考数据库服务器提供的文档。

只有在你明确使用“SELECT .... FOR UPDATE”时才成立。

如果没有“FOR UPDATE”部分,当两个事务同时运行时,第二个事务可能会在第一个事务读取值之后、但第一个事务使用它进行更新之前更改该值。

如果没有“FOR UPDATE”部分,你**绝对不能保证**在你的工作进行过程中不会有其他人进行更改。
5
harl at gmail dot com
6年前
一些数据库管理系统 (DBMS) 允许在事务中使用 DDL(表创建/修改),而另一些则不允许。询问“我的 DBMS 是否允许在事务中使用 DDL 而不强制提交?” 会得到以下示例答案

CUBRID:是
DB2 UDB:是
Firebird:是
Informix:是
MySQL:否
Oracle:否(尽管可以使用“基于版本的重新定义”来推出模式升级)
PostgreSQL:是
SQLite:是
SQL Server:有时,取决于隔离级别、命令类型等。
Sybase:是
4
pasamio at gmail dot com
12年前
通常,数据定义语言子句 (DDL) 将触发数据库引擎自动提交
https://dev.mysqlserver.cn/doc/refman/5.0/en/implicit-commit.html

许多其他数据库(例如 Oracle)将在运行 DDL 语句之前和之后隐式提交。
To Top