- 行锁(锁住的是一行记录)
- 并不是所有引擎都支持行锁,比如MyISAM,不支持行锁意味着只能使用表锁,同一时间一张表只能允许一个更新操作在执行
- 两阶段锁
- 事务A执行期间获得两个行记录锁,事务B在事务A未提交之前都会被阻塞。行锁在SQL语句执行时加上,在事务提交之后才会释放,不是说语句执行结束就会立刻释放,称之为两阶段锁协议
- 两阶段锁协议的作用?
- eg:顾客A账户在电影院B购买了一张电影票
- 需执行的SQL语句如下
- 账户A扣除金额 1
- 影院B增加金额 2
- 记录一条交易记录 3
- 此时顾客C也要购买一张电影票,那么两个事务之间存在的冲突时对语句2的执行,通过调整语句的顺序(123->132),行记录2锁的时间就会减少,使得事务之间的等待时间减少 利用两阶段锁协议调整SQL语序,从而减少事务之间的等待时间
- 需执行的SQL语句如下
- eg:顾客A账户在电影院B购买了一张电影票
- 死锁和死锁检测
- 问题:CPU消耗接近100%,数据库每秒执行不到100个数据,什么原因?
- 线程对共享资源的争夺而进入无限等待状态称为死锁,比如事务A在等待事务B释放行锁X1,事务B在等待事务A释放行锁x2
- 解决方法
- 设置超时等待时间,超时等待时间默认是50秒,这个时间对于线上服务往往是不可接受的,而如果设置成一个很小的值,那么如果是简单的锁等待,则会出现很多的误伤
- 主动死锁检测,每当一个事务被锁的时候,就会查看其所依赖的线程是否被锁住,死锁检测也有消耗,比如1000个并发线程同时更新一行数据,死锁检测复杂度O(N),如果最终检测没有死锁,那么将会耗费大量的cpu用于死锁检测也就是无用功,导致cou利用率高却执行不了几个事务
- 一种方法是如果你知道这个业务一定不会出现死锁,那么可以关闭死锁检测(默认是开启的),死锁检测是业务无损的,发生死锁回滚就好,但是关闭死锁检测就会出现大量的超时,属于业务有损的。
- 一种方式是控制并发量,如果只有10个线程在更新,那么就可以避免用于死锁检测的cpu占比高的情况,并发控制做在服务端可以是中间件/修改MySQL源码,这样对于相同行数据的更新,在进入引擎之前会先排队,而如果做在客户端,即使一个客户端10个线程,有300个客户端,并发数也会达到3000
- 如果团队没有数据库方面的专家,那么可以将一行记录拆分为逻辑多行,比如影院账户的余额由10条记录组成,那么入账的时候,写哪一行都行,但是出账的时候需要考虑行数据为0的情况(为0你得从其它记录里出账)
- 总结:根据两阶段锁协议,开发时如何调整语序,影响并发度的语句往后放,但是调整语序并不能解决死锁问题,因此引入了死锁检测和控制并发量
- 问题:当备库逻辑备份时,binlog传来ddl语句怎么处理?【得看ddl语句在底层语句执行语句时的哪个阶段到达】
- 1、无影响,备份时拿到的是ddl语句之后的表结构
- 2、无影响,备份时拿到的是ddl语句之前的表结构
- 3、备份时报错,表结构被修改
- 4、主从延迟,真正开始备份时有新数据到达
- 问题:什么时候会进行锁的检测?死锁检测要扫描所有事务吗?读操会进行死锁检测吗?
- 加锁访问的行上有锁才会检测
- 只会扫描持有锁的事务(被等待的)进行检测
- 一致性读,又叫快照读,不需要锁检测
行锁(锁住的是一行记录)
最新推荐文章于 2023-07-18 20:02:10 发布