我读到了optimistic锁定方案,客户机可以读取这些值,执行这些计算,当需要进行写操作时,在将更新写入数据库之前对其进行验证。
假设我们使用乐观锁的版本机制,那么(在两个客户机的情况下)这两个都将有如下更新语句:
更新tablename set field=val,version=oldversion+1其中
版本=旧版本,ID=X;
现在让我们考虑两个客户机的以下场景:
两个客户端都读取字段和版本的值。
两个客户都在那里计算一些东西。生成字段的新值。
现在,两个客户端都向数据库服务器发送查询请求。
一旦到达数据库:
开始执行一个客户端更新查询。
但同时会发生交错和其他客户端更新
开始执行。
这些查询交错是否会导致表中的数据竞争?
我的意思是说,我们不能说乐观锁是单独执行的,例如,我理解发生行级锁定或发生其他类似表级锁定的情况,那么就可以了。但是,它类似的乐观锁本身不起作用,它还需要悲观锁(行级/表级,这完全取决于底层存储引擎的实现)。
如果已经没有行/表级别的锁,但希望实现乐观锁定策略,会发生什么情况。使用查询交错将导致表中的数据竞争(我的意思是说只有字段被更新而版本不被更新,然后交错发生。这完全取决于为查询设置的隔离级别吗?
我对这种情况有点困惑。
还有什么是正确的用例,乐观锁定与悲观锁定相比,能够真正有帮助并提高应用程序的总体性能。

最佳答案

最坏情况下的伪代码场景:两个客户端更新同一记录:
场景1(您的场景:乐观锁定):
在服务器端检查最终约束。乐观锁定仅用于表示目的。
客户一订购的产品只有一个库存。
客户二订购同一产品,但库存只有一件。
两个客户都能在屏幕上看到这个。
产品表:

 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;

这个场景的结果是,两个订单都可以成功:它们都从第一个select中获取stock>0,然后执行订单放置。这是一种不必要的情况(几乎在任何情况下)。因此,这将不得不在代码中解决,取消订单,采取更多的交易。
场景2:乐观锁定的替代方案:
在数据库端检查最终约束。乐观锁定仅用于表示目的。在前面的乐观锁定场景中,数据库查询更少,重做的机会更少。
客户一订购的产品只有一个库存。
客户二订购同一产品,但库存只有一件。
两个客户都能在屏幕上看到这个。
产品表:
 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;

现在有两个客户展示了这个产品,同时点击Order。系统同时执行两个命令。结果将是:一个订单将被放置,另一个获得异常,因为约束将无法验证,并且事务将被中止。此中止(异常)必须在代码中处理,但不接受任何进一步的查询或事务。

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

10-10 18:11