【问题标题】:Is this update lost?此更新丢失了吗?
【发布时间】:2011-03-02 06:46:21
【问题描述】:

我只是想了解通过事务解决的“更新丢失”的含义。

请看下面两个事务,我使用mysql 5.5.8和innodb存储引擎:

create table counter (what varchar(5), id integer, count integer, primary key (id));
insert into counter values ('total', 0, 0);

      session 1 (T1)                       session 2(T2)
 -------------------------------------------------------------------------
0                               |           begin;
 -------------------------------------------------------------------------
1           begin;              |        
 -------------------------------------------------------------------------
2   select count from  counter  |
    where id = 0;               |
 -------------------------------------------------------------------------
3                               |   update counter set count = 50 
                                |   where id = 0; 
 -------------------------------------------------------------------------
4                               |   commit;
 ------------------------------------------------------------------------
5  update counter set count     |
   = 1000 where id = 0;         |
 -------------------------------------------------------------------------
6           commit;             |        
 -------------------------------------------------------------------------

您可以将值 1000 和 50 视为:

  1. 更新值1000取决于读取的count,即select。
  2. 更新值 50 取决于另一个读取(与 session1 不冲突)。

所以,这是典型的读写依赖。

session1 (T1) 提交并再次执行'select count from counter where id=0'后,计数将是1000。我想知道是不是更新丢失 还是没有?如果不是为什么?如果我没记错的话,在任何隔离级别都将避免最后的任何更新。

一种可能的解决方法是使用“从 id = 0 的计数器中选择计数进行更新;”在第 2 步,这相当于在记录上添加 xlock,因此 T2 将被阻塞。所以这是串行执行的[T1,T2]

这是 Innodb 的(已知)错误吗?注意,这不等价于执行[T2,T1],因为T1会按照这个顺序读取50个其他0,最终的结果会不一样。

谢谢

【问题讨论】:

  • 您需要描述您的实际任务,以便我们为您提供如何解决它的示例场景。
  • @zerkms,我只是想明白“更新丢失”是什么意思。
  • 在 Session2-commit 和 Session1-commit 之间,count 的值为 50,但在 Session1-commit 之后,它将就像从未更新到 50 一样。所以我们可以称更新丢失'。
  • 我认为更新丢失了,从我发现的情况来看,在这种情况下(select * from ..),innodb 将执行非锁定读取。我们至少添加一个共享锁。

标签: mysql database concurrency


【解决方案1】:

是的,当然更新丢失了。对外界而言,您的事务只有在提交时才真正“执行”。对于第三方,您的架构对应于:

  1. 会话 2 将 ID 0 的计数器更新为 50
  2. 会话 1 将 ID 0 的计数器更新为 1000

您实际上甚至不需要为此进行交易:交易没有任何区别。如果您的会话 1 在会话 2 进行更新后进行选择,它们将很重要。在这种情况下,如果有事务,会话 1 将读取值 0,但如果没有事务,它将读取值 50。

【讨论】:

  • 我只是不知道怎么用mysql shell编程,你可以认为更新的值(50和1000)取决于count的值。
  • @Chang 什么,为什么需要在 mysql shell 中编程?请注意,对于事务,您可以通过发出 select count from counter where id = 0 for update; 来防止丢失更新。再说一次,这样的事情通常取决于时间,并且您几乎无法控制哪个事务将首先命中数据库
  • @nos,我不需要在 my-sql shell 中编程,实际上,我想说的是 1000 和 50 是从计数中计算出来的。顺便说一句,我更新了我的问题。
【解决方案2】:

这是因为 INNODB 默认隔离级别REPEATABLE READ

【讨论】:

    【解决方案3】:

    是的,您的情况正是丢失更新的含义。在 postgresql 中,T1 将被 dbms 中止以防止丢失更新。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-02-21
      • 2013-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-31
      • 2016-05-26
      • 2015-05-23
      相关资源
      最近更新 更多