我有一个关于我们使用SELECT FOR UDPATE
的目的的问题?它到底是做什么的?
我有2个表,我需要从表中选择行,并更新相同的行。
例如:
选择查询
SELECT * from t1 WHERE city_id=2 for update
更新查询
UPDATE t1 SET final_balance = final_balance - 100 WHERE city_id ='2'
我的问题是,这是否真的锁定了读取操作,直到我的更新完成,或者它到底处理了什么?
我的想法是,在我的更新完成之前,没有人可以读取/更新这些行。
2条答案
按热度按时间sc4hvdpw1#
SELECT ... FOR UPDATE
将使用写(排他)锁锁定记录,直到事务完成(提交或回滚)。要选择记录并确保在更新之前不对其进行修改,您可以启动一个事务,使用
SELECT ... FOR UPDATE
选择该记录,执行一些快速处理,更新该记录,然后提交(或回滚)该事务。如果在事务之外使用
SELECT ... FOR UPDATE
(自动提交打开),则锁仍将立即释放,因此请确保使用事务来保留锁。为了提高性能,不要让事务打开很长时间,因此应该立即进行更新。
bwntbbo32#
在MySQL中,SELECT FOR UPDATE用于防止更新丢失。*在MySQL中,只有SERIALIZABLE才能防止丢失更新而不使用SELECT FOR UPDATE,但在SERIALIZABLE中出现了死锁,所以我们应该使用SELECT FOR UPDATE,即使是SERIALIZABLE。
接下来,在MySQL上,我会先向您展示更新丢失,然后是选择更新,如何防止更新丢失。
例如,有**“产品”表**,包含**“id”、“名称”和“股票”**,如下所示。*当客户购买产品时,产品库存减少:
Id|名称|股票
-|-|
1|苹果|10
2|橙色|20
首先,下面这些步骤不使用SELECT FOR UPDATE在MySQL上显示UPDATE丢失:
Flow|Transaction 1(T1)|Transaction 2(T2)|说明
-|-|
第一步|
BEGIN;
||T1启动。第二步||
BEGIN;
|T2启动。第三步|
SELECT stock FROM product WHERE id = 2;
20||t1读20,后因客户购买7个橙子,更新为13。Step 4||
SELECT stock FROM product WHERE id = 2;
20|t2读20,因为客户买了4个橘子,所以更新为16。Step 5|
UPDATE product SET stock = '13' WHERE id = 2;
||t1将20更新为13。Step 6|
COMMIT;
||t1提交。Step 7||
UPDATE product SET stock = '16' WHERE id = 2;
|T2在T1提交后将13更新为16。Step 8||
COMMIT;
|t2提交,#*更新丢失其次,下面这些步骤展示了如何在MySQL上使用SELECT FOR UPDATE防止更新丢失:
Flow|Transaction 1(T1)|Transaction 2(T2)|说明
-|-|
第一步|
BEGIN;
||T1启动。第二步||
BEGIN;
|T2启动。Step 3|
SELECT stock FROM product WHERE id = 2 FOR UPDATE;
20||当选择更新时,T1读为20,后续更新为13,因为客户购买了7个橘子。Step 4||
SELECT stock FROM product WHERE id = 2 FOR UPDATE;
|t2需要等待t1提交读取stock,并带有SELECT FOR UPDATE。Step 5|
UPDATE product SET stock = '13' WHERE id = 2;
|正在等待...|T1将20更新为13。第六步|
COMMIT;
|正在等待...|T1提交。Step 7||
SELECT stock FROM product WHERE id = 2 FOR UPDATE;
13|现在加上SELECT FOR UPDATE,T2的读数是13,因为客户买了4个橘子,所以以后会更新为9。Step 8||
UPDATE product SET stock = '9' WHERE id = 2;
|T2在T1提交后将13更新为9。步骤9||
COMMIT;
|t2提交,#*不丢失更新