mysql - 乐观锁和交错

标签 mysql database concurrency

我阅读了有关乐观锁定方案的信息,其中客户端可以读取值,在那里执行计算,并且在需要进行写入时,在写入数据库之前验证更新。

比方说,如果我们为乐观锁采用版 native 制,那么(在两个客户端的情况下)两者都会有更新语句:

update tableName Set field = val, version = oldVersion +1 其中 version = OldVersion and Id = x;

现在让我们考虑以下具有两个客户端的场景:

  1. 两个客户端读取字段和版本的值。
  2. 两个客户端都在最后计算一些东西。产生新的字段值。
  3. 现在两个客户端都向数据库服务器发送查询请求。

    一旦到达数据库: 一个客户端更新查询开始执行。 但与此同时发生交错和其他客户端更新 开始执行。

这些查询交错会导致表中的数据竞争吗 我的意思是说,我们不能说乐观锁是自己执行的,例如我理解发生行级锁定或其他像表级锁定这样的锁定的情况,那就没问题了。 但是它像乐观锁本身不起作用,它还需要悲观锁(行级/表级,这完全取决于底层存储引擎实现)。

当没有行/表级别的锁时会发生什么,但想要实现开放式锁定策略。使用查询交错会导致表中的数据竞争。(我的意思是说只有字段被更新而版本没有更新然后交错发生。这完全取决于为查询设置的隔离级别)?

我对这种情况有点困惑。

此外,与悲观锁定相比,乐观锁定真正有用并提高应用程序整体性能的正确用例是什么。

最佳答案

最坏情况的伪代码场景:两个客户端更新同一条记录:

场景 1(您的场景:乐观锁定):

在服务器端检查最终约束。乐观锁定仅用于演示目的。

Client one orders a product of which there is only 1 in stock.

Client two orders the same product of which there is only 1 in stock.

两个客户端都将其呈现在屏幕上。

产品表:

 CREATE TABLE products (
   product_id VARCHAR(200),
   stock INT,
   price DOUBLE(5,2)
 ) ENGINE=InnoDB;

演示代码:

 -- Presentation:
 SELECT * FROM products WHERE product_id="product_a";
 -- Presented to client

订购代码:

 -- Verification of record (executed in the same block of code within 
 -- an as short time interval as possible):
 SELECT stock FROM products WHERE product_id="product_a";
 IF(stock>0) THEN
 -- Client clicks "order" (one click method=also payment);
   START TRANSACTION;
     -- Gets a record lock
     SELECT * FROM products WHERE product_id="product_a" FOR UPDATE; 
     UPDATE products SET stock=stock-1 WHERE product_id="product_a";
     INSERT INTO orders (customer_id,product_id,price) 
       VALUES (customer_1, "product_a",price);
   COMMIT;
 END IF;

The result of this scenario is that both orders can succeed: They both get the stock>0 from the first select, and then execute the order placement. This is an unwanted situation (in almost any scenario). So this would then have to be addressed in code by cancelling the order, taking a few more transactions.

场景 2:乐观锁定的替代方案:

在数据库端检查最终约束。乐观锁定仅用于演示目的。与之前的乐观锁定方案相比,数据库查询更少,重做的机会更少。

Client one orders a product of which there is only 1 in stock.

Client two orders the same product of which there is only 1 in stock.

两个客户端都将其显示在屏幕上。

产品表:

 CREATE TABLE products (
   product_id VARCHAR(200),
   stock INT,
   price DOUBLE(5,2),
   CHECK (stock>=-1) -- The constraint preventing ordering
 ) ENGINE=InnoDB;

演示代码:

 -- Presentation:
 SELECT * FROM products WHERE product_id="product_a";
 -- Presented to client

订购代码:

 -- Client clicks "order" (one click method=also payment);
 START TRANSACTION;
   -- Gets a record lock
   SELECT * FROM products WHERE product_id="product_a" FOR UPDATE; 
   UPDATE products SET stock=stock-1 WHERE product_id="product_a";
   INSERT INTO orders (customer_id,product_id,price) 
     VALUES (customer_1, "product_a",price);
 COMMIT;

So now two customers get presented this product, and click order on the same time. The system executes both orders simultaneous. The result will be: One order will be placed, the other gets an exception since the constraint will fail to verify, and the transaction will be aborted. This abort (exception) will have to be handled in code but does not take any further queries or transactions.

关于mysql - 乐观锁和交错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31639539/

相关文章:

mysql - 如何创建一个 "connection"表,其中包含MySQL中两个单独表的信息?

php - CodeIgniter 错误为 foreach() 提供的参数无效

mysql - 尝试定义我的表时收到错误

go - 为什么Goroutines与顺序执行所花的时间几乎相同?

jquery - 处理数据传递的适当方法 MySQL->JSON->PHP?

mysql - 如何从联接中的子查询访问父列

ssh - Golang - 到多个节点的并发 SSH 连接

java - 使用预定义 key 锁定的竞争条件解决方案

mysql - 唯一目的是指定另一个表的子集的表

mysql - ./configure 在树莓派 3 上找不到 libmysqlclient 库,无法链接