共享锁(读锁)/排他锁(写锁)

读锁与写锁区别

语法

// 读锁
select ... lock in share mode
// 写锁
select ... for update

共同点

  1. 都是作用在 select 语句中
  2. A 事务对某 select 语句加锁之后(未提交事务),其他事务无法对该数据执行修改操作(update/delete)
  3. 只有当 A 事务提交或回滚,其他事务才能对数据进行修改操作(update/delete)
  4. 不管读锁还是写锁,它们都属于悲观锁的一种形式

不同点

  1. 读锁:当 A 事务对 select 语句加上读锁时,其他事务对 select 加上读锁获取数据不会阻塞
  2. 写锁:当 A 事务对 select 语句加上写锁时,其他事务对 select 加上读锁/写锁获取数据阻塞,只有等待 A 事务提交或回滚,其他事务才能读取到数据

读锁写锁示例

假设有张 user 表,表中数据如下
共享锁(读锁)/排他锁(写锁)

读锁(共享锁)

------------------A事务------------------ ------------------B事务------------------
对 id = 1 的数据增加读锁,但是并不提交事务
共享锁(读锁)/排他锁(写锁)
不加锁的查询,查询成功
共享锁(读锁)/排他锁(写锁)
加上读锁查询,查询成功
共享锁(读锁)/排他锁(写锁)
对 id = 2 的数据进行修改,修改成功
共享锁(读锁)/排他锁(写锁)
对 id = 1 的数据进行修改,修改出现阻塞
共享锁(读锁)/排他锁(写锁)
事务提交
共享锁(读锁)/排他锁(写锁)
由于 A事务 commit 了,阻塞状态取消,修改成功
共享锁(读锁)/排他锁(写锁)

写锁(排他锁)

------------------A事务------------------ ------------------B事务------------------
对 id = 1 的数据增加写锁,但是并不提交事务
共享锁(读锁)/排他锁(写锁)
不加锁的查询,查询成功
共享锁(读锁)/排他锁(写锁)
加上写锁查询 id = 2 的数据,查询成功
共享锁(读锁)/排他锁(写锁)
加上写锁查询 id = 1 的数据,查询出现阻塞
共享锁(读锁)/排他锁(写锁)
事务提交
共享锁(读锁)/排他锁(写锁)
由于 A事务 commit 了,阻塞状态取消,查询成功
共享锁(读锁)/排他锁(写锁)
对 id = 1 的数据增加写锁,但是并不提交事务
共享锁(读锁)/排他锁(写锁)
修改 id = 2 的数据,修改成功
共享锁(读锁)/排他锁(写锁)
修改 id = 1 的数据,修改出现阻塞
共享锁(读锁)/排他锁(写锁)
事务提交
共享锁(读锁)/排他锁(写锁)
由于 A事务 commit 了,阻塞状态取消,修改成功
共享锁(读锁)/排他锁(写锁)

注意事项

注意注意注意:for update 仅适用于InnoDB,并且必须开启事务,在begin与commit之间才生效。或者在代码中使用@Transactional才能生效。

行锁:访问数据库的时候,锁定整个行数据,防止并发错误。 如InnoDB存储引擎使用行锁
表锁:访问数据库的时候,锁定整个表数据,防止并发错误。 如MyISAM存储引擎使用表锁

例1:明确指定主键,并且数据真实存在,行锁

select status from t_goods where id = 1 for update;

例2:明确指定主键,但数据不存在,无锁

select status from t_goods where id = 0 for update;

例3:主键不明确,表锁

select status from t_goods where id <= 3 for update;

例4:无主键,表锁

select status from t_goods for update;

共享锁(读锁)/排他锁(写锁)

上一篇:Jquery应用实例


下一篇:Reflect