事务和自动提交

现已通过 PDO 连接,在开始发布查询之前,您必须了解 PDO 如何管理事务。如果之前从未遇到的事务,它们提供了 4 大特点:原子性、一致性、隔离性和持久性 (ACID)。通俗地说,事务中执行的任何工作,即使是分阶段执行,一旦提交都会得到安全地应用到数据库中,并且不会受到其他连接的干扰。还可以根据您的要求自动撤消事务性工作(前提是没有提交),这使得脚本中错误处理变得更加容易。

事务通常通过“保存”一批要一次性应用的更改来实现;这有一个不错的附带效果就是大幅提高了这些更新的效率。换句话说,事务可以让您的脚本更快,并且还有可能更稳定(您仍需正确使用它们才能获得这些好处)。

不幸的是,并非每个数据库都支持事务,因此 PDO 在您首次打开连接时需要运行在“自动提交”模式下。自动提交模式意味着您运行的每个查询都有它自己的隐式事务,如果数据库支持该事务,否则则没有事务。如果您需要事务,则必须使用 PDO::beginTransaction() 方法来启动事务。如果底层驱动程序不支持事务,则会抛出一个 PDOException(无论您的错误处理设置如何:这始终是一种严重的错误状态)。一旦进入事务,便可以使用 PDO::commit()PDO::rollBack() 根据事务期间运行的代码的成功程度来完成事务。

警告

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

这方面的一个示例就是在 MySQL 数据库上的 MyISAM 表上尝试使用事务。

如果在脚本结束或即将关闭连接时仍然有未完成的事务,PDO 会自动将其回滚。这是一种安全措施,以帮助避免在脚本意外终止时发生不一致的情况——如果您没有明确提交事务,则认为出现了问题,因此为保护您的数据安全,执行回滚。

警告

仅当您通过 PDO::beginTransaction() 启动事务时,才会执行自动回滚。如果您手动发出启动事务的查询,PDO 无从得知,因此在发生问题时也无法将它回滚。

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

在以下示例中,我们假设我们为一名已被分配 23 号 ID 的新员工创建一组条目。除了输入该人的基本数据之外,我们还需要记录他们的工资。进行两次单独的更新非常简单,但可以通过将它们括在 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 个注释

hooby404 at gmail dot com
2 年前
> 你不必在事务中对更新进行限制;你还可以发出复杂
> 查询以提取数据,还有可能使用该信息来构建更多更新
> 和查询;在事务处于活动状态时,你可以确保在处理工作时
> 其他任何人都不可能进行更改。有关
> 事务的进一步阅读,请参考数据库服务器提供的文档。

只有在专门执行“SELECT .... FOR UPDATE”时才成立。

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

如果没有“FOR UPDATE”部分,绝对不能确保在处理工作时其他任何人都不可能进行更改。
harl at gmail dot com
6 年前
一些 DBMS 允许在事务中使用 DDL(表创建/更改),一些则不允许。询问“我的 DBMS 是否允许在事务中使用 DDL 而不用强制提交?”会提供以下示例答案

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

许多其他数据库(例如,Oracle)将在运行 DDL 语句前后自动提交。
To Top