MySQL锁机制
前言
通过学习《高性能MySQL》记下的一些笔记
MySQL锁机制
并发控制
多个查询需要在同一时刻修改数据,会产生并发控制的问题,利用锁机制来解决
读写锁
- 共享锁/排他锁:读锁/写锁
- 读锁是共享的,多个用户可以在同一时刻读取同一个数据
- 写锁是排他的,某一个写锁会阻塞其余的读写锁
锁粒度
更有选择性的锁定对象可以提高共享资源的并发性,加锁也会消耗资源
MyISAM默认使用表级锁,且不支持行级锁
InnoDB默认使用行级锁,且支持表级锁
InnoDB在使用索引时,默认使用行级锁,没有使用索引时,默认使用表级锁
表锁
是MySQL中最基本的锁策略,开销最小,采用读写锁机制
- 一个用户在进行写操作(插入,删除,更新)前,需要先获得写锁,这会阻塞其他用户的读写操作,读锁之间并不互斥
行级锁
行级锁可以最大程度地支持并发处理,但是会牺牲一定的资源
乐观锁与悲观锁
- 悲观锁:认为每次读取数据别人都会修改数据,表锁和行锁都是悲观锁
- 乐观锁:认为每次读取数据都没有人修改数据,不对数据上锁,但是在提交更新的时候会判断在此期间数据是否被修改,若被更改则提交失败,利用MVCC(多版本并发控制)来实现乐观锁
死锁
两个或多个事务在同一资源上相互占用,并请求锁定对方的资源。
- InnoDB存储引擎,能检测到死锁的循环依赖,并立即返回一个错误
- 当查询的时间达到锁等待超时的设定放弃锁请求
- InnoDB当前的策略:将持有最少行级排他锁的事务进行回滚
多版本并发控制(MVCC)
- MVCC是行级锁的变种,乐观锁的实现
- 保存数据在某一时间点的快照来实现
- InnoDB中,通过在每行记录后保存行的创建时间和删除时间作为版本号
- 在InnoDB中的READ COMIITED和REPEATABLE READ两种隔离级别下,事务对于select会访问版本链
- InnoDB中聚簇索引中有两个必要的隐藏列:trx_id用来存储某个聚簇索引记录修改时的事务id, roll_pointer是一个指针,指向聚簇索引修改时老版本存在的undo日志中
- ReadView
- 两种隔离级别生成ReadView的策略不同
- ReadView是一个存储着当前活跃事务的列表(开始且未提交的事务)
- 查询时,会找到可以访问的最新版本进行访问
ReadView中主要包含4个比较重要的内容:
- m_ids:表示在生成ReadView时当前系统中活跃的读写事务的事务id列表。
- min_trx_id:表示在生成ReadView时当前系统中活跃的读写事务中最小的事 务id,也就是m_ids中的最小值。
- max_trx_id:表示生成ReadView时系统中应该分配给下一个事务的id值。
- creator_trx_id:表示生成该ReadView的事务的事务id。
有了这个ReadView,这样在访问某条记录时,只需要按照下边的步骤判断记录的某个版本是否可见:
- 如果被访问版本的trx_id属性值与ReadView中的creator_trx_id值相同,意 味着当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。
- 如果被访问版本的trx_id属性值小于ReadView中的min_trx_id值,表明生成 该版本的事务在当前事务生成ReadView前已经提交,所以该版本可以被当前事 务访问。
- 如果被访问版本的trx_id属性值大于ReadView中的max_trx_id值,表明生成 该版本的事务在当前事务生成ReadView后才开启,所以该版本不可以被当前事 务访问。
- 如果被访问版本的trx_id属性值在ReadView的min_trx_id和max_trx_id之间 ,那就需要判断一下trx_id属性值是不是在m_ids列表中,如果在,说明创建Re adView时生成该版本的事务还是活跃的,该版本不可以被访问;如果不在,说 明创 建ReadView时生成该版本的事务已经被提交,该版
本可以被访问
————————————————
原文链接:https://blog.****.net/nmjhehe/article/details/98470570