行锁是由引擎层实现,MyISAM不支持,InnoDB支持,行锁可以提高并发度
两阶段锁说起:
两阶段锁协议:InnoDB事务中,行锁在需要的时候才添加,并不是不需要的时候释放,而是在事务提交时才释放
因此假如事务中需要锁多个行,要把最可能出现锁冲突的锁放在最后,因为这样可以减少锁等待的时间,提高并发度
这样解决了行锁占用时间过长的问题,但是还是有可能发生死锁?
死锁构建:事务A 需要id =1 和2 的锁 ,事务B需要id=2 和1 的锁 ,事务A拿到1的锁等待2的锁,事务B拿到2的锁等待1的锁 ,进入死锁
两种策略解决:
1.(不推荐)超时参数innodb_lock_wait_timeout,默认50s,发生竞争,等待,知道超时
2.(推荐)死锁检测,设置innodb_deadlock_detect,默认on,开启,发现死锁,主动回滚某个事务,让其他事务继续执行
推荐策略也会有热点问题:
由于死锁检测时间复杂度是O(N),那么如果1000个并发,将会有100w个死锁检测,消耗大量CPU资源,可能出现CPU利用率很高,但是每秒执行不了多少事务
解决方式:
1.(不适合)临时关闭死锁检测,会有风险可能出现大量超时
2.控制并发度,客户端限制,不合适,因为无法确定客户端数量,即使限制几个并发,客户端数量大,并发也会很大,因此必须限制在服务端,操作比较难
3.(建议思考)可以将记录处理位多行,这样可以减少锁冲突,但是要对业务进行详细设计
问题:
如果你要删除一个表里面的前 10000 行数据,有以下三种方法 可以做到:
第一种,直接执行 delete from T limit 10000; 不好,单个语句占用时间长,锁的时间比较长,大事务还会导致主从延迟
第二种,在一个连接中循环执行 20 次 delete from T limit 500;比较好
第三种,在 20 个连接中同时执行 delete from T limit 500;不好,人为造成了锁冲突