当前位置: 首页 > 知识库问答 >
问题:

乐观锁和交错

房学文
2023-03-14

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

假设如果我们为乐观锁采用版本机制,那么(在两个客户端的情况下)两者都将具有更新语句,如下所示:

更新表名称集字段 = val,版本 = 旧版本 1,其中版本 = 旧版本,ID = x;

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

>

  • 两个客户端都读取字段和版本的值。
  • 两个客户端都在那里计算一些东西。生成字段的新值。
  • 现在两个客户端都向数据库服务器发送查询请求。

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

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

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

    我对这种情况有点困惑。

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

  • 共有1个答案

    翟源
    2023-03-14

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

    方案 1(方案:乐观锁定):

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

    客户一订购的产品只有1个库存。

    客户2订购了相同的产品,但库存只有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;
    

    这个场景的结果是两个订单都可以成功:他们都获得了<code>股票

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

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

    客户一订购的产品只有1个库存。

    客户2订购了相同的产品,但库存只有1件。

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

    产品表:

     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;
    

    现在有两个顾客收到了这个产品,同时点击了订单。系统同时执行两个订单。结果将是:一个订单将被发出,另一个订单将得到一个异常,因为约束将无法验证,并且交易将被中止。这个中止(异常)必须用代码来处理,但不需要任何进一步的查询或事务。

     类似资料:
    • 悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作 乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。 乐观锁与悲观锁的具体区别: http://www.cnblogs.com/Bob-FD/p/3352216.html

    • 在多用户环境中,在同一时间可能会有多个用户更新相同的记录,会产生冲突,解决方案有两种:乐观锁、悲观锁。 悲观锁在这里不讲,自行Google。 乐观锁假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性,不完整则更新失败。 乐观锁实现方式 使用整数表示数据版本号.更新时检查版本号是否一致,如果相等,则更新成功,且版本号+1.如果不等,则数据已经被修改过,更新失败。 使用时间戳来实现。 本质上也

    • 本文向大家介绍说一下乐观锁和悲观锁?相关面试题,主要包含被问及说一下乐观锁和悲观锁?时的应答技巧和注意事项,需要的朋友参考一下 乐观锁:每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。 悲观锁:每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻止,直到这个锁被释放。 数据库的乐观锁需要自

    • 乐观锁Version 要使用乐观锁,需要使用version标记 type User struct { Id int64 Name string Version int `xorm:"version"` } 在Insert时,version标记的字段将会被设置为1,在Update时,Update的内容必须包含version原来的值。 var user User engine

    • 我们有一个系统,我们偶尔会得到一个乐观的锁定异常。我们在代码中已经解决了这个问题,但现在我正在查看JPA 2,并看到它有一个用于处理这个问题的注释(@版本) 我们的问题是,一个表上有多个事务,如果表锁已满,则即使未对相同的记录进行更改,也会导致乐观锁定异常。 我们在JBoss 4.2服务器上使用hibernate,数据库可以是MySQL或SQL服务器。 如果改为使用@Version,这会在两个数据

    • 当我试图理解基于版本的乐观锁定如何防止“最后提交获胜”问题和适当的覆盖时,我遇到了困难。 为了使问题更具体,让我们考虑以下使用 JDBC 的伪代码: 这里,如果其他事务会在更新和提交之间提交其更改呢?如果事务是并发的,那么第一个事务所做的更新尚未提交,因此第二个事务不可见(具有适当的隔离级别),因此第一个事务提交将覆盖第二个交易的更改,而不会出现任何通知或错误。 乐观锁定只是降低了问题发生的概率,