我读过乐观锁定方案,客户端可以读取值,在那里执行计算,当需要写入时,更新会在写入数据库之前得到验证。
如果我们为乐观锁使用版本机制(万一有两个客户端),那么两个客户端都将具有update语句如下:
update tableName Set字段= val,version = oldVersion +1,其中version = OldVersion和Id = x;
现在,让我们考虑以下两个客户端的场景:
这些查询交织会导致表中的数据竞争吗?我的意思是,我们不能说乐观锁是单独执行的,例如,我理解行级锁定发生的情况,或者其他类似于表级锁定的锁定发生的情况,然后就可以了。但是其类似的乐观锁不能单独工作,它还需要悲观锁(行级/表级,这完全取决于底层存储引擎的实现)。
如果没有行/表级别的锁,但希望实现乐观锁定策略,会发生什么情况。使用查询交织会导致表中的数据竞争。(我的意思是说,只有字段被更新,版本没有更新,然后发生交织。)这完全取决于为查询设置了哪些隔离级别)?
我对这种情况有点困惑。
另外,什么是正确的用例,与悲观锁定相比,乐观锁定可以真正帮助并提高应用程序的总体性能。
发布于 2015-07-27 15:19:21
最坏情况下的伪代码场景:两个客户端更新相同的记录:
场景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:乐观锁定的替代方案:
最后的约束将在数据库端检查。乐观锁定仅用于表示目的。与以前的乐观锁定方案相比,数据库查询较少,出现redos的可能性也较小。
客户一订购的产品,其中只有一个库存。 客户两个订单相同的产品,其中只有一个在库存。
这两个客户端都在屏幕上显示。
产品表:
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;因此,现在有两个客户得到了这个产品,并点击订单在同一时间。系统同时执行两个命令。结果将是:一个订单将被放置,另一个将获得异常,因为约束将无法验证,事务将被中止。此中止(异常)必须在代码中处理,但不需要进行任何进一步的查询或事务处理。
https://stackoverflow.com/questions/31639539
复制相似问题