加锁目的
解决客户端并发访问数据库产生的冲突问题
锁粒度
锁粒度即通常所说的锁级别
应该尽量只锁定需要修改的那部分数据,而不是所有的资源。锁定的数据量越少,发生锁争用的可能就越小,系统的并发程度就越高。 但是加锁需要消耗资源,锁的各种操作(包括获取锁、释放锁、以及检查锁状态)都会增加系统开销。因此封锁粒度越小,有关锁的操作就越频繁,系统开销就越大。
Mysql提供三种锁级别:页级锁,表级锁,行级锁
- MyISAM和MEORY存储引擎采用表级锁;
- DB存储引擎采用的是页面锁,也支持表级锁;
- InnoDB存储引擎支持行级锁也支持表级锁默认情况下采用行级锁
Mysql三种锁特性:
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
锁类型
- 读锁(共享锁): 简称S锁 ;select : 加读锁以后别人不能更改表记录,但可以进行查询 一个事务对数据对象(数据库、表、页或者行) 加了 S 锁,可以对 A 进行读取操作,但是不能进行更新操作。加锁期间其它事务能对 A 加 S 锁,但是不能加 X 锁。
- 写锁(排他锁,互斥锁):简称X锁; insert 、 delete 、 update 加写锁之后别人不能查、不能改。 一个事务对数据对象(数据库、表、页或者行)加了 X 锁,就可以对 A 进行读取和更新。加锁期间其它事务不能对 A 加任何锁。
死锁和活锁(摘自博文https://blog.csdn.net/fantalee/article/details/81661665 )
1. 活锁
假设事务T1封锁了某数据对象(数据库,表,页,行)R,事务T2也申请封锁R,此时T2处于等待状态;可是当事务T1释放R后,系统允许新来的事务T3封锁了R,T2仍然处于等待状态;从此往后,T2一直处于等待状态。类似于操作系统中线程的“饥饿”状态。解决办法就是排队,采用先来先服务的策略,系统按照申请数据对象R的先后顺序排队。
2. 死锁
事务T1封锁了数据对象R1,又申请封锁R2,;
事务T2封锁了数据对象R2;又申请封锁R1.
两者形成死锁。死锁预防:
1)一次封锁法:事务一次将所要使用的数据对象全部封锁,否则不能执行。
2)顺序封锁法:所有事务都按照一个顺序封锁数据对象。
死锁诊断和解除:
诊断:使用事务等待图,它动态地反映所有事务的等待情况,并发控制子系统周期性地检测事务等待图,只要在图中出现回路,就说明存在死锁。
解除:通常选择处理代价最小的事务,将其回滚,释放所有它持有的封锁,使其他事务能继续执行下去。