先放个网络美女提提神
MySQL的行级锁是由各个引擎自己实现的,innodb支持行级锁但MyISAM却不支持,这也是innodb更受青睐的原因之一。
想要高效使用innodb的行级锁,必须要熟悉两阶段锁协议和死锁预防。
两阶段锁协议
-
定义
事务执行时,在运行到需要加锁的语句时加锁,但不是对应语句执行完了就释放锁,而是等到commit时才会释放锁。
如图1所示,session1在t1时刻对id=1的行加锁了。在t4时刻session2想要更新id=1的行,这是会被阻塞,因为id=1的行锁需要等到t5时刻session1 commit后才会被释放。
对程序的影响
在编写程序时,程序员应当尽量将需要请求行锁的代码放到离commit更近的地方。
死锁预防措施
-
我们知道死锁发生的条件
- 多个资源互斥访问
- 资源被获取后不可抢占
- 多个线程循环等待
-
在数据库行级锁场景下,这些条件都会被满足,因此对于行级锁的请求肯定会造成死锁。那我们应当如何解决死锁呢,有如下两种办法:
死锁检测
著名的死锁检测方法就是银行家算法,不知道的小伙伴可以查一下。但这有个非常大的缺点,每次死锁检测的时间复杂度为O(N),因此如果有1000个线程要执行加锁操作时就会带来100万级别的时间复杂度开销。控制并发度
很好理解,线程数越少死锁发生的概率越小。可以通过控制统一时刻访问同一行的请求数量来控制并发度以减少死锁发生的概率。另一种方式就是将数据分散,比如数据库中原来有一行数据记录用户在银行的存款数额,现在将其拆分成10行,10行数额的相加就是这个用户的存款数,当一个请求要修改该用户的存款数额的时候,就随机从10行中选一行进行操作,这样就将并发度减少为了1/10。