Mysql的行锁和表锁

1.解决事务一致性方案

1.LBCC 基于锁的并发控制

基于锁的来实现事务隔离,一个事务读取的时候不允许其他事务修改,意味着Lock Based Concurrency Control(LBCC)不支持并发的读写操作,而大多应用读多写少,这样会影响操作数据的效率。

2.MVCC 多版本的并发控制

多版本的并发控制Multi Version Concurrency Control (MVCC)。
核心思想:可以查到这个事务之前已经存在的数据,即使他已经被修改或删除了,在这个事务之后新增的数据,查不到。

问题:快照什么时候创建?读取数据的时候,怎么保证能读取到这个快照而不是最新的数据?这个怎么实现呢?
InnoDB每行记录都有两个隐藏字段:
DB_TRX_ID,6字节:插入或更新行的最后一个事务的事务ID,自增(可以理解为创建版本号)
DB_ROLL_PTR,7字节:回滚指针(删除版本号)

在InnoDB 中,MVCC 是通过Undo log 实现的。

2 行锁和表锁的区别

  1. 锁定粒度,行锁大于表锁
    表锁,锁住一张表
    行锁,锁住里面的一行数据

  2. 加锁效率,表锁大于行锁。
    表锁只需锁住这张表就行
    行锁需要在表里检索这一行数据

  3. 冲突概率表锁大于行锁
    锁住整张表,其他任何事务都不能操作这张表
    锁住一行,其他事务可以操作未被锁的行

3 行锁–共享锁 Shared Locks

获取共享锁和可以读取数据,也叫读锁。
多个事务可以共享一把读锁。
加读锁: select …… lock in share mode;
释放锁有两种方式:事务结束(提交事务和结束事务)

4 行锁–排它锁 Exclusive Locks

主要功能:操作数据,又称写锁
只要一个事务获取了一行数据的排他锁,其他事务就不能再获取该行的共享锁和排他锁。
加锁方式: 1.自动加排他锁
2.手工加锁 FOR UPDATE

5 表锁–意向锁

数据库自己维护的
加了共享锁钱,自动加意向共享锁
加了排他锁前,自动加意向排他锁

为什么加表锁?

  1. InnoDB可以支持更多粒度的锁
  2. 提升加锁的效率。加行锁前可以判断意向锁,如果有则返回失败,如果没有,则加锁成功。如果没有意向锁则需要扫描整张表。

总结:锁是用来解决事务对数据的并发访问的问题的


为什么表里面没有索引的时候,锁住一行数据会导致锁表?
如果锁住的是索引,一张表没有索引怎么办?
1)定义了主键,InnoDB会选主键作为聚集索引。
2)没有显示定义主键,会选第一个不包含null值的唯一索引作为主键索引
3)如果也没有2中的索引,则选择内置6字节长的RoWID作为隐藏的聚集索引,它会随着记录的写入递增。
所以,锁表是因为没有使用索引,进行全表扫描,把每一个隐藏的聚集索引都锁住了。

为什么通过唯一索引给数据行加锁,主键索引也会被锁住?
唯一索引也是辅助索引,存储的是二级索引和主键的值。主键索引存放了索引和完整的数据。通过辅助索引锁定一行数据的时候,会通过主键值找到主键索引然后也锁定。


锁的算法 --(记录锁,间隙锁,临键锁)

记录锁

对唯一性的索引(包括唯一索引和主键索引)使用等值查询,精确匹配到一条记录的时候,使用的就是记录锁。

间隙锁

当查询记录不存在,没有命中任何一个,无论用等值还是范围查询,都是间隙锁
注意,间隙锁主要是阻塞插入insert。相同的间隙锁之间不冲突。

临键锁

范围查询,命中了记录,还包含了间隙,就是临键锁。
默认的行锁算法,相当于记录锁加间隙锁。
临键锁,锁住最后一个key 的下一个左开右闭的区间。

为什么要锁住下一个左开右闭的区间?
—就是为了解决幻读的问题。

为什么有些公司要用RC,或者说网上有些文章推荐有RC?
RC 和RR 主要有几个区别:
1、RR 的间隙锁会导致锁定范围的扩大。
2、条件列未使用到索引,RR 锁表,RC 锁行。
3、RC 的“半一致性”(semi-consistent)读可以增加update 操作的并发性。

InnoDB 的行锁,就是通过锁住索引来实现的。

死锁

锁的释放与阻塞

锁什么时候释放?
事务结束(commit,rollback);客户端连接断开。

死锁发生和监测

死锁的产生条件。
因为锁本身是互斥的,(1)同一时刻只能有一个事务持有这把锁,(2)其他的事务需要在这个事务释放锁之后才能获取锁,而不可以强行剥夺,(3)当多个事务形成等待环路的时候,即发生死锁。

为什么可以直接检测到呢?
是因为死锁的发生需要满足一定的条件,所以在发生死锁时,InnoDB 一般都能通过算法(wait-for graph)自动检测到。

show status like ‘innodb_row_lock_%’;

如何避免死锁
1、在程序中,操作多张表时,尽量以相同的顺序来访问(避免形成等待环路);
2、批量操作单张表数据的时候,先对数据进行排序(避免形成等待环路);
3、申请足够级别的锁,如果要操作数据,就申请排它锁;
4、尽量使用索引访问数据,避免没有where 条件的操作,避免锁表;
5、如果可以,大事务化成小事务;
6、使用等值查询而不是范围查询查询数据,命中记录,避免间隙锁对并发的影响。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值