锁定资料 Lock

MySQL 交易 Transaction: 锁定资料 Lock

锁定资料有 shared lock (sharedLock)lock for update (lockForUpdate),两者都可以避面同一行资料被其他的 transaction update

不同的地方

定义

sharedLock locks only for write, lockForUpdate also prevents them from being selected

shared lock (sharedLock)lock for update (lockForUpdate) 两者都是锁定类型的 transaction,但这两个锁定类型的 transaction 不会避免非锁定的 transaction 去读取到资料。

sharedLock

其他的 Session 可以 Select,但无法 Update 资料

如果 Session_1 使用 sharedLock 去读取资料并对资料进行修改,而 Session_2 也使用 sharedLock 去读取资料并对资料进行修改,则 Session_2 会等到 Session_1 commit 之后,才能对资料进行 update,若 Session_1 与 Session_2 都有修改到同样栏位资料,则会变成最后修改的 Session_2 的资料。

使用情境

parentchild 两个资料表,而两者资料是有关联性的,当要新增资料至 child 资料表时,必须确保 parent 资料表有资料,才不会让 child 找不到他的 parent,此时可以使用 sharedLock 去避免资料被异动(删除、更新)

SELECT * FROM parent WHERE NAME = 'Jones' FOR SHARE;

lockForUpdate

可以避免被其他锁定型 transaction 进行 Select

当需要对同一栏位确保资料 update 是正确的,如计数器,则必须使用 lockForUpdate 来锁定资料

parent 内有一个计数器栏位纪录总共有多少 child,则为了数字正确更新,必须避免其他锁定型的 transaction 进行资料异动

SELECT counter_field FROM child_codes FOR UPDATE;
UPDATE child_codes SET counter_field = counter_field + 1;

NOWAIT & SKIP LOCKED

NOWAIT

若有资料被锁定,不会等待其他 transaction commit 后再去读取资料,直接抛出错误

SKIP LOCKED

若有资料被锁定,不会等待其他 transaction commit 后再去读取资料,直接忽略该资料

范例

Session 1 锁定资料

--
# Session 1:

mysql> CREATE TABLE t (i INT, PRIMARY KEY (i)) ENGINE = InnoDB;

mysql> INSERT INTO t (i) VALUES(1),(2),(3);

mysql> START TRANSACTION;
-- 锁定资料 2 的资料,避免被读取
mysql> SELECT * FROM t WHERE i = 2 FOR UPDATE;
+---+
| i |
+---+
| 2 |
+---+

Session 2 捞取资料,使用 NOWAIT


# Session 2:

mysql> START TRANSACTION;
-- NOWAIT 遇到资料 2 被 Lock 抛出错误
mysql> SELECT * FROM t WHERE i = 2 FOR UPDATE NOWAIT;
ERROR 3572 (HY000): Do not wait for lock.

Session 3 捞取资料,使用 SKIP LOCKED

# Session 3:

mysql> START TRANSACTION;

-- SKIP LOCKED 遇到资料 2 被 Lock,忽略资料 2
mysql> SELECT * FROM t FOR UPDATE SKIP LOCKED;
+---+
| i |
+---+
| 1 |
| 3 |
+---+

参考资料