【问题标题】:How to solve Concurrency issue?如何解决并发问题?
【发布时间】:2017-02-10 12:54:50
【问题描述】:

全部,

我在我的应用程序中使用 MySql 5.7。我试图使我的保存功能并发安全。我将举例说明。

示例: 我有两个管理员用户 Admin 1 和 Admin 2。我们有一个产品表,我们有一个产品表条目,产品代码为“P1”。假设 Admin 1 和 Admin 2 登录到系统并尝试同时使用代码“P1”更新产品条目。

我需要通知其中一位用户您正在尝试修改的记录正在由另一位用户更新,并在一段时间后重试。

我正在使用事务并且没有更改 MySql 的默认事务级别(可重复读取)。我正在尝试通过使用“SELECT FOR UPDATE”来解决它(包括一个 where 条件来检查修改时间)。这个“where”条件将解决那些已经提交的事务的并发问题。但是如果两个事务同时启动并且第一个事务在锁超时之前被提交,那么当第二个事务执行时,它会覆盖第一个事务。

欢迎分享你的想法

提前致谢

【问题讨论】:

  • 您可以在临界区出现之前执行LOCK TABLES product WRITE。之后别忘了解锁。
  • @apokryfos 锁定整个表以完成单个记录的编辑并不是真正有效的解决方案
  • 我想这可能是解决方案之一:使用 InnoDB 引擎和select ... for update
  • 有一种古老的技术是在表中创建一个版本字段。每次更新注册表时,它都会有版本,因此管理员 1 将拥有版本 1,管理员 2 也将拥有版本 1,当其中一个更新注册表时,通过触发器增加版本(检查它是否是相同版本)当管理员 2 尝试更新触发器时,将检查版本是否已过时并抛出异常。

标签: php mysql validation concurrency


【解决方案1】:

其实这里有两个问题。

首先,其中一个管理员将在另一个之前获得行上的锁,因此假设 admin1 先获得锁,admin2 将排队,直到 admin1 的事务完成,然后 admin2 的事务才会发生。

所以这一切都由 DBMS 为您处理。

但第二个问题当然是 admin1 和 admin2 是否都在尝试更新相同的列。在这种情况下,admin1 的更新将被 admin2 的更新覆盖。如果您想要停止这种情况,那么阻止这种情况发生的唯一方法是使 UPDATE 非常具体地说明它正在更新的内容。换句话说,UPDATE 必须是这样的

UPDATE table SET col1 = 'NewValue' 
WHERE usual criteria
  AND col1 = 'Its Original Value'

因此,这意味着当您在表单中将此行中的原始数据呈现给用户时,您必须以某种方式记住其原始状态,并捕获管理员将其更改为的新状态。

当然,还必须编写 PHP 代码来捕捉更新未发生的事实,并向管理员更新失败的情况返回一些内容。在相关列中显示新值,并通知他们更新失败,因为其他人已经更改了该字段,让他们要么忘记那里的更改,要么将他们的更改应用到其他管理员更新的顶部。

【讨论】:

    【解决方案2】:

    您可以使用这种技术来控制它,而无需锁定表或控制您应该执行的更新。

    在您的表上创建一个字段,作为该注册表的版本:

    alter table someTable add column version not null integer default 0;
    

    无需更改任何插入代码。

    每次用户获取注册表进行更新时,请确保它在对象(或表单、m 或您在系统中处理实体的任何方式)中也有版本。

    然后您将需要为您的表创建一个before update trigger,它将检查当前注册表的版本是否仍然相同,如果不是则更新您会引发错误。比如:

    delimiter $$
    create trigger trg_check_version BEFORE UPDATE
             ON yourTable 
             for each row
        begin
            if NEW.version != OLD.version then
                signal sqlstate '45000' set message_text = 'Field outdated';
            else
               NEW.version = NEW.version + 1; 
            end if;
        end$$
    delimiter;
    

    然后你处理你的 php 代码中的错误。此signal 命令仅适用于 MySql 5.5 或更高版本。看看这个thread

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-08
      • 2021-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-20
      • 1970-01-01
      • 2010-10-11
      相关资源
      最近更新 更多