2 个用户同时更新记录


2 users updating a record at the same time

我想知道在以下假设情况下会发生什么。假设两位老师给同一个学生上完全相同的课,他们都想更新学生的成绩。鲍勃目前的平均值是 60%,教师 1 想用他得到 70% 的测试来更新他的平均值,老师 2 想用他得分为 40% 的测试来更新他的平均值。

那么在 1 到 100 万的几率中,两位老师同时按下更新按钮,恰好同时按下一瞬间,会发生什么?它会给出错误消息,php 或 mysql 会神奇地排队更新吗,只有第一个分数更新 bob 的平均值和第二个用户会得到错误吗?

编辑

:我担心的是第二个用户必须在第一个用户编辑值后获取值,我正在考虑获取记录,然后在 php 中进行计算,然后再次更新记录,但在这种情况下,我如何确保第二个用户获取的值为 65% 而不是 60%, 这可以通过交易来完成吗?

它们不能同时运行操作,总会有很小的差异,因为机器在物理上不可能同时写入相同的信息。可能是几微秒或更短的问题,但差异会在那里。

通常的解决方案之一是在WHERE子句中添加类似的数据,并检查是否已完成更新:

UPDATE students SET `avg` = '70' WHERE id=<some-id> AND `avg` = '60';

但是,像平均值这样的东西通常最好不要以这种方式更新:有一个单独的学生分数表,并自己计算每个学生的这些记录的平均值(如果你愿意,你仍然可以在学生表中"缓存"它)。

两者都会通过,最后一个要处理的值将是新值。由于数据库系统的一致性保证,您不会获得损坏的数据,但由于这是一个计算值,您可能会得到错误的数据。

我怀疑这个平均值是基于其他表格中的数据的计算值。如果是这种情况,请在一个事务中完成所有工作。将新的测试分数添加到表中,并让数据库计算平均值并将结果直接插入第二个表中。这样,要么保证结果正确,要么交易失败。这需要一个支持事务的存储引擎(例如,InnoDB)。

数据库将按顺序更新行。其中一个查询将首先运行,锁定行(有时是表-取决于查询),下一个查询将排队,直到第一个查询完成。

如果操作是原子的,你不会遇到任何麻烦。你的插入是。两个插入都将被执行。

不过要小心非原子操作!

这就是交易跳入的地方:http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_transaction

悲观的锁定和交易只是这里故事的一半。数据库将取出行锁,但这只能确保任何尝试修改同一行的人都必须等到当前事务完成。我想防止的情况是:

  1. 教师 A 查看作业,看不到成绩。
  2. 教师 b 查看作业,看不到成绩。
  3. 教师 A 分配 70 年级。
  4. 教师 b 分配 40 年级。

b很可能不是要覆盖a的意思。最好的保护是某种形式的乐观锁定。当两个人同时进行编辑时,您会在wiki中看到这一点。后来的提交者必须确认编辑,因为它可能会意外地撤消早期提交者的更改。在评分情况下,您可以在 where 子句中添加向用户显示的旧成绩,然后断言更新更改了一行。

UPDATE GRADES SET SCORE=70 WHERE NAME='Jim' AND SCORE=0;