如何在MySQL中使用事务来避免“丢失更新”?

时间:2017-09-20 06:57:51

标签: mysql sql concurrency transactions

  

当两个不同的交易尝试时,会发生丢失的更新   更新数据库中同一行上的同一列   时间。通常,一个事务更新a中的特定列   特别是一排,而另一个在不久之后就开始了   在更新相同的值之前不会看到此更新。结果   然后第一个交易被“丢失”,因为它只是被覆盖   通过第二次交易。 - https://morpheusdata.com/blog/2015-02-21-lost-update-db

enter image description here

3 个答案:

答案 0 :(得分:1)

这也被称为“竞争条件”。您已经在问题中得到了答案:您“使用交易”,您是否工作,然后COMMIT每个线程中的交易。现在的细节:

  • 如果输入InnoDB
  • ,您的表必须是
  • 默认情况下,MySQL连接每个命令使用1个事务,基本上每次写入后自动提交数据。您需要START TRANSACTION或禁用PHP中的自动提交:$mysqli->autocommit(FALSE);,例如
  • 你需要注意你的操作结果和ROLLBACK错误并停止你正在做的事情
  • 完全完成后,您必须记住COMMIT您的更改,否则,系统会认为您出现了错误并ROLLBACK

答案 1 :(得分:0)

你有两种可能性

  1. 如果出现悲观锁定,如果您打算更新刚才读取的数据,请选择更新。然后只有一个人可以读取记录,直到当前交易完成,其他人试图选择更新,必须等待。
  2. 如果是乐观锁定,则需要制定update-statement,以便在select和update之间发生更改时,不会发生更新。在您的情况下,您可以使用:

    UPDATE product set quantity = 10 
           where id = 1 and quantity = <original quantity -- 7>
    

    如果不是预期的记录数(通常为1)已更新,因为数量的更新已由另一个进程同时完成,那么您必须在更新之前重复选择。 你怎么知道,有多少记录已被更新?这取决于您用来执行db请求的技术,但根据我的经验,每个Sql-Dbms都会将该信息返回给客户端。

答案 2 :(得分:0)

无论

  

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

- 遭遇一些死锁和一点性能损失   - 没有它看起来那么糟糕,但取决于你的需求   - REPEATABLE READ是InnoDB的默认级别

OR

  

选择更新

- 好吧,你写了代码,你知道哪些选择需要锁定其他人   - 这假设您的隔离级别为READ_COMMITTED

有关隔离级别的更多内容可以在MySql文档中找到(这次简短明了) https://dev.mysql.com/doc/refman/5.5/en/innodb-transaction-isolation-levels.html