跳至主要內容

排它锁和共享锁

张威大约 5 分钟mysqlmysql锁机制

排它锁和共享锁

排它锁(Exclusive),又称为X锁,写锁共享锁(Shared),又称为S锁,读锁

,但是

对事务加X和S锁之间有以下的关系:

  • 一个事务对数据对象A加了 S 锁,可以对A进行,加锁期间

  • 一个事务对数据对象A加了 X 锁,就可以对A进行,加锁期间其它事务

显式加锁:

select … lock in share mode #强制获取共享锁
selectfor update #获取排它锁

测试不同事务之间排它锁和共享锁的兼容性

我们先查看键表的SQL以及内容

查看隔离级别:

首先开启一个事务,给id=7的数据加上排它锁,我们用另一个事务的服务线程给id=7的数据加上排它锁,阻塞了

我们尝试给id=7的数据加上共享锁,还是;再获取id=8的共享锁和排它锁,可以成功获取id=8的共享锁和排它锁

小结:不同事务之间对于数据的锁,只有SS锁可以共存,XX、SX、XS都不能共存

测试行锁加在索引项上

其实行锁是加在索引树上的

事务1用表的无索引字段age作为过滤条件;事务2现在同样想获取这条记录的排它锁,可想而知地了;那现在事务2获取不同行chenwei的记录的排它锁,

。然而现在我们发现获取age=20的排它锁也获取不到了,这是为什么?我们解释一下:

而我们用age作为过滤条件没有用到索引,自然就不会使用行锁,而是使用表锁。这就意味着只有通过索引检索数据,InnoDB才使用行级锁,如果做整表扫描,InnoDB将使用表锁!!!

  • 两个事务可以获取到不同行的排它锁(for update),再一次证明了InnoDB的行锁是加在索引项上的
  • 是如果使用相同的索引字段(zhangsan)作为过滤条件,依然会发生锁冲突,只能串行进行,不能并发进行。

因为现在name走的是索引, 通过zhangsan在辅助索引树上找到它所在行记录的id是1,然后到主键索引树上,获取对应行记录的排他锁(MySQL Server会根据情况,在主键索引树和辅助索引树上加锁)

串行化隔离级别测试

在SERIALIZABLE隔离级别下,所有的事务都自动使用排它锁或共享锁,不需要用户手动加锁(for in share mode/for update)

两个事务可以同时获取共享锁(SS共存),事务2插入数据

  • 此时由于insert需要加排它锁,但由于
  • 因为我们给name加上了索引,以上的select相当于给name为zhangsan的数据加上了行共享锁
  • ,因为此时已经被事务1的

事务2在辅助索引树上找zhangsan,找到对应的主键值,然后去主键索引树找到相应的记录,但是发现这行记录已经被共享锁锁住了,事务2可以获取共享锁,但是不能获取排他锁

我们用主键索引id试试能不能update

依然阻塞住了,虽然我们where后面的字段现在使用的id而不是name,但是name也是通过辅助索引树找到对应的主键,再到主键索引树上找相应的记录,而主键索引树上的记录加了锁MySQL Server会根据情况,在主键索引树和辅助索引树上加锁

我们update id=8的数据,成功了。因为我们select的时候,只是给id=7 name=zhangsan的数据加上了行锁,我们操作id=8的数据当然可以成功

注意

有索引,则使用行锁;没有索引,则使用表锁。

表级锁还是行级锁说的是锁的粒度,共享锁和排他锁说的是锁的性质,不管是表锁还是行锁,都有共享锁和排他锁的区分