MySQL中的乐观锁定

Gre*_*orn 31 mysql sql database locking optimistic

我在MySQL中找不到乐观锁定的任何细节.我读到,启动事务会保持同步的两个实体的更新,但是它不会阻止两个用户同时更新数据而导致冲突.

显然乐观锁定会解决这个问题吗?这是如何在MySQL中应用的.这有SQL语法/关键字吗?或者MySQL有默认行为吗?

多谢你们.

Die*_*aro 108

关键是乐观锁定不是数据库功能,不适用于MySQL,也不适用于其他人:乐观锁定是使用带有标准指令的DB应用的实践.

让我们有一个非常简单的例子,并说你想在多个用户/客户端可以并发运行的代码中执行此操作:

  1. 从具有一个ID字段(iD)和两个数据字段(val1,val2)的行中选择数据
  2. 可选择使用数据进行计算
  3. 更新该行的数据

NO LOCKING方式是:

注意:所有代码{在curl brakets之间}都应该在应用程序代码中,而不是(必要地)在SQL端

- SELECT iD, val1, val2
       FROM theTable
       WHERE iD = @theId;
 - {code that calculates new values}
 - UPDATE theTable
       SET val1 = @newVal1,
           val2 = @newVal2
       WHERE iD = @theId;
 - {go on with your other code}
Run Code Online (Sandbox Code Playgroud)

OPTIMISTIC LOCKING方式是:

- SELECT iD, val1, val2
       FROM theTable
       WHERE iD = @theId;
 - {code that calculates new values}
 - UPDATE theTable
       SET val1 = @newVal1,
           val2 = @newVal2
       WHERE iD = @theId
           AND val1 = @oldVal1
           AND val2 = @oldVal2;
 - {if AffectedRows == 1 }
 -     {go on with your other code}
 - {else}
 -     {decide what to do since it has gone bad... in your code}
 - {endif}
Run Code Online (Sandbox Code Playgroud)

请注意,关键点在于UPDATE指令的结构以及随后的受影响行数.正是这两件事让你的代码意识到有人已经在执行SELECT和UPDATE之间修改了数据.请注意,所有事情都没有交易!这是可能的(没有事务)只是因为这是一个非常简单的例子,但这也说明乐观锁定的关键点不在事务本身.

那么TRANSACTIONS怎么样?

 - SELECT iD, val1, val2
       FROM theTable
       WHERE iD = @theId;
 - {code that calculates new values}
 - BEGIN TRANSACTION;
 - UPDATE anotherTable
       SET col1 = @newCol1,
           col2 = @newCol2
       WHERE iD = @theId;
 - UPDATE theTable
       SET val1 = @newVal1,
           val2 = @newVal2
       WHERE iD = @theId
           AND val1 = @oldVal1
           AND val2 = @oldVal2;
 - {if AffectedRows == 1 }
 -     COMMIT TRANSACTION;
 -     {go on with your other code}
 - {else}
 -     ROLLBACK TRANSACTION;
 -     {decide what to do since it has gone bad... in your code}
 - {endif}
Run Code Online (Sandbox Code Playgroud)

最后一个示例显示,如果您在某个时刻检查了冲突并发现已经修改了其他表/行时发生了冲突.. ..然后使用事务,您可以回滚自那以后所做的所有更改一开始.显然,取决于您(知道您的应用程序正在做什么)来决定每次可能的冲突回滚的操作量有多大,基于此决定放置事务边界的位置以及检查与特殊冲突的位置的位置UPDATE + AffectedRows检查.

在这种情况下,事务我们将执行UPDATE的时刻与提交时的时刻分开.那么当"其他进程"在这段时间内执行更新时会发生什么?要知道究竟发生了什么,需要深入了解隔离级别的细节(以及如何在每个引擎上进行管理).作为使用READ_COMMITTED的Micosoft SQL Server的一个例子,更新的行被锁定,直到COMMIT,因此"其他进程"不能对那些行做任何事情(等待),既不是SELECT(实际上它只能READ_COMMITTED) .因此,由于"其他进程"活动被推迟,因此UPDATE将失败.

VERSIONING OPTIMISTIC LOCKING选项:

 - SELECT iD, val1, val2, version
       FROM theTable
       WHERE iD = @theId;
 - {code that calculates new values}
 - UPDATE theTable
       SET val1 = @newVal1,
           val2 = @newVal2,
           version = version + 1
       WHERE iD = @theId
           AND version = @oldversion;
 - {if AffectedRows == 1 }
 -     {go on with your other code}
 - {else}
 -     {decide what to do since it has gone bad... in your code}
 - {endif}
Run Code Online (Sandbox Code Playgroud)

这里显示的是,不是检查所有字段的值是否仍然相同,我们可以使用专用字段(每次我们进行更新时修改)以查看是否有人比我们更快并更改了我们之间的行选择和更新.这里没有事务是由于第一个例子中的简单性而与版本列的使用无关.此列的使用再次取决于应用程序代码中的实现,而不是数据库引擎功能.

除此之外还有其他一些观点,我认为这个答案太长了(已经太长了)所以我现在只提到它们一些参考文献:

  • 有关SELECTs的事务影响的事务隔离级别(此处为MySQL).
  • 对于与主键不自动生成的(或唯一约束)表的INSERT它会自动失效,无需特别的检查,如果两个进程试图插入它必须是唯一的值相同.
  • 如果您没有id列(主键或唯一约束),则单个SELECT + UPDATE也需要事务,因为您可能会遇到意外,而不是在其他人进行修改之后,有比预期更多的行匹配UPDATE的WHERE子句的条件.

如何检查实践并获得信心

由于隔离级别值和实现可能不同,因此最佳建议(通常在此站点中)是对使用的平台/环境执行测试.

这似乎很难,但实际上它可以很容易地从任何DB developmemt环境使用两个独立的窗口,并在每一个启动事务,然后通过一个执行命令一个完成.

在某些时候,您将看到命令执行无限期地继续.然后在另一个窗口上,它被称为COMMIT或ROLLBACK,它完成执行.

以下是一些非常基本的命令,可以像刚刚描述的那样进行测试.

使用这些来创建表和一个有用的行:

CREATE TABLE theTable(
    iD int NOT NULL,
    val1 int NOT NULL,
    val2 int NOT NULL
)
INSERT INTO theTable (iD, val1, val2) VALUES (1, 2 ,3);
Run Code Online (Sandbox Code Playgroud)

然后在两个不同的窗口上逐步进行以下操作:

BEGIN TRAN

SELECT val1, val2 FROM theTable WHERE iD = 1;

UPDATE theTable
  SET val1=11
  WHERE iD = 1 AND val1 = 2 AND val2 = 3;

COMMIT TRAN
Run Code Online (Sandbox Code Playgroud)

然后以您可能想到的任何顺序更改命令的顺序和执行顺序.

  • 很棒的答案.非常感谢你! (4认同)
  • 您可能会出错的一件事是在 SQL Server 中,有一个“rowversion”数据类型专为此特定用途而设计。 (2认同)