首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >乐观锁与交错

乐观锁与交错
EN

Stack Overflow用户
提问于 2015-07-26 16:53:52
回答 1查看 1K关注 0票数 2

我读过乐观锁定方案,客户端可以读取值,在那里执行计算,当需要写入时,更新会在写入数据库之前得到验证。

如果我们为乐观锁使用版本机制(万一有两个客户端),那么两个客户端都将具有update语句如下:

update tableName Set字段= val,version = oldVersion +1,其中version = OldVersion和Id = x;

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

  1. 两个客户端都读取字段和版本的值。
  2. 两个客户端都计算一些东西。生成字段的新值。
  3. 现在,两个客户端都向数据库服务器发送查询请求。 一旦到达数据库:一个客户端更新查询就开始执行。但与此同时,交织发生了,其他客户端更新也开始执行。

这些查询交织会导致表中的数据竞争吗?我的意思是,我们不能说乐观锁是单独执行的,例如,我理解行级锁定发生的情况,或者其他类似于表级锁定的锁定发生的情况,然后就可以了。但是其类似的乐观锁不能单独工作,它还需要悲观锁(行级/表级,这完全取决于底层存储引擎的实现)。

如果没有行/表级别的锁,但希望实现乐观锁定策略,会发生什么情况。使用查询交织会导致表中的数据竞争。(我的意思是说,只有字段被更新,版本没有更新,然后发生交织。)这完全取决于为查询设置了哪些隔离级别)?

我对这种情况有点困惑。

另外,什么是正确的用例,与悲观锁定相比,乐观锁定可以真正帮助并提高应用程序的总体性能。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-07-27 15:19:21

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

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

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

客户一订购的产品,其中只有一个库存。 客户两个订单相同的产品,其中只有一个在库存。

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

产品表:

代码语言:javascript
复制
 CREATE TABLE products (
   product_id VARCHAR(200),
   stock INT,
   price DOUBLE(5,2)
 ) ENGINE=InnoDB;

表示代码:

代码语言:javascript
复制
 -- Presentation:
 SELECT * FROM products WHERE product_id="product_a";
 -- Presented to client

订单代码:

代码语言:javascript
复制
 -- 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:乐观锁定的替代方案:

最后的约束将在数据库端检查。乐观锁定仅用于表示目的。与以前的乐观锁定方案相比,数据库查询较少,出现redos的可能性也较小。

客户一订购的产品,其中只有一个库存。 客户两个订单相同的产品,其中只有一个在库存。

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

产品表:

代码语言:javascript
复制
 CREATE TABLE products (
   product_id VARCHAR(200),
   stock INT,
   price DOUBLE(5,2),
   CHECK (stock>=-1) -- The constraint preventing ordering
 ) ENGINE=InnoDB;

表示代码:

代码语言:javascript
复制
 -- Presentation:
 SELECT * FROM products WHERE product_id="product_a";
 -- Presented to client

订单代码:

代码语言:javascript
复制
 -- 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;

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31639539

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档