了解pdo mysql事务

Web*_*eng 18 php mysql pdo transactions

PHP文件说:

如果您以前从未遇到过交易,它们提供了4个主要功能:原子性,一致性,隔离和耐用性(ACID).通俗地说,任何在交易中进行的工作,即使是分阶段进行的,也可以保证安全地应用于数据库,并且在承诺时不受其他连接的干扰.

题:

这是否意味着我可以有两个单独的PHP脚本同时运行事务而不会相互干扰?


通过 " 干扰 "来实现我的意思:

想象一下,我们有下employees表:

 __________________________
|  id  |  name  |  salary  |
|------+--------+----------|
|  1   |  ana   |   10000  |
|------+--------+----------|
Run Code Online (Sandbox Code Playgroud)

如果我有两个具有相似/相同代码的脚本,并且它们在同一时间运行:

script1.phpscript2.php(两者都有相同的代码):

$conn->beginTransaction();

$stmt = $conn->prepare("SELECT * FROM employees WHERE name = ?");
$stmt->execute(['ana']);
$row = $stmt->fetch(PDO::FETCH_ASSOC);

$salary = $row['salary'];
$salary = $salary + 1000;//increasing salary

$stmt = $conn->prepare("UPDATE employees SET salary = {$salary} WHERE name = ?");
$stmt->execute(['ana']);

$conn->commit(); 
Run Code Online (Sandbox Code Playgroud)

并假设事件序列如下:

  • script1.php选择数据

  • script2.php选择数据

  • script1.php更新数据

  • script2.php更新数据

  • script1.php commit()发生了

  • script2.php commit()发生了

在这种情况下,ana的薪水是多少?

  • 它会是11000吗?那么这是否意味着1个事务将与另一个事务重叠,因为信息是在提交之前获得的?

  • 它会是12000吗?那么这是否意味着无论数据更新和选择的顺序如何,该commit()功能都会强制这些单独发生?

请随意详细说明事务和单独脚本如何相互干扰(或不干扰).

Sha*_*dow 14

你不会在php文档中找到答案,因为这与php或pdo无关.

mysql中的Innodb表引擎提供了符合sql标准的4个所谓的隔离级别.隔离级别与阻塞/非阻塞读取一起将确定上述示例的结果.您需要了解各种隔离级别的含义,并根据您的需要选择合适的隔离级别.

总结一下:如果在关闭自动提交的情况下使用可序列化隔离级别,则结果将为12000.在所有其他隔离级别中,并且启用自动提交的可序列化结果将为11000.如果您开始使用锁定读取,则结果可能是在所有隔离级别下12000.


You*_*nse 9

根据给定的条件(一个单独的DML语句)判断,这里不需要事务,而是表锁.这是一个非常普遍的混乱.

如果您需要确保所有DML语句都已正确执行或根本未执行,则需要进行事务处理.

手段

  • 您不需要任何数量的SELECT查询的事务
  • 如果只执行一个DML语句,则不需要事务

虽然,正如Shadow中的优秀答案所指出的那样,你可以在这里使用具有适当隔离级别的事务,但这会相当混乱.你需要的是表锁定.InnoDB引擎允许您锁定特定行而不是锁定整个表,因此应该是首选.

如果你想要薪水是1200 - 然后使用表锁.

或者 - 更简单的方法 - 只需运行原子更新查询:

UPDATE employees SET salary = salary + 1000 WHERE name = ?
Run Code Online (Sandbox Code Playgroud)

在这种情况下,将记录所有工资.

如果您的目标不同,请更好地明确表达.

但同样重要的是:你必须明白,事务通常与单独的脚本执行无关.关于竞争条件的主题,您不了解交易,而是对表/行锁定感兴趣.这是一个非常常见的混淆,你最好直接学习它:

  • 事务是确保一组DML查询中一个脚本成功执行.
  • 表/行锁定是为了确保其他脚本执行不会干扰.

事务和锁定干扰的唯一主题是死锁,但同样 - 只有在事务使用锁定时才会出现这种情况.


Ric*_*mes 5

唉,“无干扰”需要程序员的一些帮助。它需要BEGINCOMMIT定义“交易”的范围。和...

你的例子是不够的。第一个语句需要SELECT ... FOR UPDATE. 这告诉事务处理很可能会UPDATE出现获取的行SELECT。该警告对于“防止干扰”至关重要。现在时间线是这样的:

  • script1.php 开始
  • script2.php 开始
  • script1.php 选择数据 ( FOR UPDATE)
  • script2.php选择数据被阻塞,所以等待
  • script1.php 更新数据
  • script1.php commit() 发生
  • script2.php 选择数据(并将获得新提交的值)
  • script2.php 更新数据
  • script2.php commit() 发生

(注意:这不是“死锁”,只是“等待”。)