如果您之前从未遇到过交易,则会提供4个专业 特性:原子性,一致性,隔离性和耐久性(ACID)。在 外行的条款,在交易中进行的任何工作,即使是 分阶段进行,保证应用于数据库 安全,并且没有其他连接的干扰,当它是 提交。
问题:
这是否意味着我可以同时运行两个独立的php脚本而不会相互干扰?
按照我的意思做好准备“ INTERFERING ”:
想象一下,我们有以下employees
表:
__________________________
| id | name | salary |
|------+--------+----------|
| 1 | ana | 10000 |
|------+--------+----------|
如果我有两个代码相似/相同的脚本并且它们在同一时间运行:
script1.php 和 script2.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();
并假设事件序列如下:
script1.php 选择数据
script2.php 选择数据
script1.php 更新数据
script2.php 更新数据
script1.php commit()发生
script2.php commit()发生
在这种情况下,ana的薪水是多少?
是11000吗?这是否意味着1个事务将与另一个事务重叠,因为信息是在提交之前获得的?
它会是12000吗?那么这是否意味着无论数据的更新和选择顺序如何,commit()
函数都会强制它们单独发生?
请随意详细说明交易和单独脚本如何相互干扰(或不干扰)。
答案 0 :(得分:14)
你不会在php文档中找到答案,因为这与php或pdo无关。
mysql中的Innodb表引擎提供符合sql标准的4个所谓的isolation levels。隔离级别与阻塞/非阻塞读取一起将确定上述示例的结果。您需要了解各种隔离级别的含义,并根据您的需要选择合适的隔离级别。
总结一下:如果在关闭自动提交的情况下使用可序列化隔离级别,则结果将为12000.在所有其他隔离级别中,启用自动提交的可序列化结果将为11000.如果您开始使用锁定读取,则在所有隔离级别下,结果可能是12000。
答案 1 :(得分:9)
根据给定的条件(单独的DML语句)判断,这里不需要事务,而是表锁。这是一个非常普遍的混乱。
如果您需要确保所有DML语句都已正确执行或根本未执行,则需要进行交易。
意味着
虽然正如Shadow中的优秀回答中所指出的那样,可能在这里使用具有适当隔离级别的事务,但这会让人感到困惑。您需要的是 table locking 。 InnoDB引擎允许你lock particular rows而不是锁定整个表,因此应该是首选。
如果您希望薪水为1200,那么请使用表锁。
或者 - 更简单的方法 - 只需运行原子更新查询:
UPDATE employees SET salary = salary + 1000 WHERE name = ?
在这种情况下,所有工资都将被记录下来。
如果您的目标不同,请更好地明确表达。
但同样重要的是:您必须了解一般的交易与单独的脚本执行无关。关于竞争条件的主题,您不了解交易但是在表/行锁定中。这是一个非常常见的混淆,你最好直接学习它:
事务和锁定干扰的唯一主题是deadlock,但同样 - 仅在事务使用锁定的情况下。
答案 2 :(得分:4)
BEGIN
和COMMIT
来定义交易的范围'。和...
你的榜样不足。第一个语句需要SELECT ... FOR UPDATE
。这告诉事务处理,UPDATE
提取的行可能会有SELECT
。该警告对于防止干扰至关重要。现在时间表上写着:
FOR UPDATE
)(注意:这不是'死锁',只是'等待'。