介紹
FOR UPDATE 是一種行級(jí)鎖,又叫排它鎖。僅適用于 InnoDB,并且必須開啟事務(wù),在 BEGIN 與 COMMIT 之間才生效。
準(zhǔn)備
- 創(chuàng)建表
CREATE TABLE `goods_order` (
`id` bigint NOT NULL AUTO_INCREMENT,
`order_number` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '訂單編號(hào)',
`user_id` bigint DEFAULT NULL COMMENT '下單用戶id',
`goods_id` bigint DEFAULT NULL COMMENT '商品id',
`state` int DEFAULT NULL COMMENT '1:待支付 2:已支付 3:已關(guān)閉',
`create_time` datetime DEFAULT NULL COMMENT '創(chuàng)建時(shí)間',
`update_time` datetime DEFAULT NULL COMMENT '更新時(shí)間',
PRIMARY KEY (`id`),
UNIQUE KEY `order_number` (`order_number`)
)
開始
開啟兩個(gè) MySQL 命令窗口
- 命令窗口1
BEGIN
SELECT id, user_id, goods_id, state FROM goods_order WHERE id = 2 FOR UPDATE
UPDATE goods_order SET state = 2 WHERE id=2
COMMIT
- 命令窗口2
BEGIN
SELECT id, user_id, goods_id, state FROM goods_order WHERE id = 2 FOR UPDATE
UPDATE goods_order SET state = 3 WHERE id=2
COMMIT
當(dāng) 命令窗口1 執(zhí)行完 SELECT ... FOR UPDATE 后(此時(shí)事務(wù)還未結(jié)束), 命令窗口2 執(zhí)行 SELECT ... FOR UPDATE 語句時(shí)將會(huì)阻塞在那,直到 命令窗口1 中的事務(wù)結(jié)束(執(zhí)行完 COMMIT)。
其中一個(gè)使用場(chǎng)景是用于修改訂單狀態(tài),修改訂單狀態(tài)往往需要兩個(gè)步驟:
- 查詢訂單狀態(tài)。
- 修改訂單狀態(tài)。
當(dāng)有兩個(gè)任務(wù)同時(shí)請(qǐng)求時(shí),有可能出現(xiàn)如下情況:
- 任務(wù)A查詢到訂單狀態(tài)為1。
- 任務(wù)B查詢到訂單狀態(tài)為1。
- 任務(wù)A修改訂單狀態(tài)為2。
- 任務(wù)B修改訂單狀態(tài)為3。
其中,任務(wù)B將訂單狀態(tài)改為3的前提是訂單狀態(tài)為1,但是上述情況下任務(wù)B修改訂單時(shí)訂單狀態(tài)已變成2了,并不符合預(yù)期,通過 SELECT ... FRO UPDATE 就可以解決上述問題。