一文读懂MySQL事务与mvcc、锁的关系

什么是mvcc?

目的:提高事务的并发性能。
原则:写加锁,读不加锁,读写不冲突,只有写写才冲突。
具体措施:保存数据库每个修改的版本,增加两个字段创建时间和删除时间,分别存储创建和删除的事务ID,作为版本号。

事务处理的常见问题?

脏读:读取未提交的数据,该数据可能会回滚。
不可重复读:两次读取的数据不一致,针对的update。
幻读:读取同一范围的数据,读取的行记录不一样,有新增行或者删除行。
更新丢失:一个事务的更新,被另一个事务的更新给覆盖了。

事务的acid是怎么保证的?

基于CopyOnWrite机制,写时复制技术,修改时复制一个新的版本,从而保证了读写不冲突,也就是mvcc。
对DML(insert、delete、update、或者显示锁),每次都加锁,同时保证写读取的数据是最新提交的。
根据事务的隔离级别选择读取mvcc的哪个版本。
RC:mvcc当前读,每次读最新的版本。
RR:mvcc快照读,晚于当前版本号的不可见。

MySQL的RR隔离级别存在什么问题?

尽管解决了幻读问题,但是仍然存在更新丢失的问题。
第一类更新丢失问题,回滚覆盖,撤销一个事务时,在该事务内的写操作要回滚,把其他已提交事务的数据也被覆盖了。
经验证,MySQL已经杜绝了该类问题的发生。

https://img-blog.csdnimg.cn/20190527235434398.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NlYW54d3E=,size_16,color_FFFFFF,t_70

第二类更新丢失问题,更新覆盖。提交一个事务时,写操作依赖于事务内读到的数据,读发生在其他事务提交之前,写发生在其他事务提交之后,把其他已提交事务的写入覆盖了。

https://img-blog.csdnimg.cn/20190527235415511.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NlYW54d3E=,size_16,color_FFFFFF,t_70

参考:https://blog.csdn.net/seanxwq/article/details/90614370

更新丢失的解决办法?

1、原子操作,update ... set a = a + 1。
2、加锁:
1)最好加排他锁select ... for update,共享锁有可能会带来死锁问题。
共享锁的锁定行后面有更新操作,容易造成死锁。
参考:https://www.jianshu.com/p/beddb45070bb
2)乐观锁,增加一个版本号列。
update ... set a = 10 where id = 1 and version = 10
判断是否更新成功,如果更新失败,需要重新更新。极端情况下,会需要多次重试。
PS:自旋的递归调用不能放在同一个事务里,因为RR级别下是允许可重复读的。
乐观锁和悲观锁的选择(阿里建议):
1、写多使用悲观锁,冲突概率超过20%,重试次数超过3次,都最好使用悲观锁。
2、金融等敏感信息使用悲观锁。乐观锁冲突的解决策略较复杂,容易处理不当。
参考:https://www.jianshu.com/p/bfd7c684412d

RR隔离级别一定能解决幻读问题吗?

读->写->读,第二次读取的快照版本和第一次读的快照版本不一样。事务开始时,读取一个快照版本,写操作会触发刷新快照版本。
参考:https://blog.csdn.net/u011277123/article/details/107868336

采用RC隔离级别,如何规避不可重复读和幻读的问题?

不可重复度:1)只读取一次,本地缓存,不要重复的多次去读取。2)使用select … lock in share mode 或者 select … for update。
幻读:不要使用范围查询,尽量使用唯一查询命中,杜绝间隙锁的使用。

RU隔离级别下,是如何加锁的呢?

这种情况下,未提交的修改也可以读,是不是没有加锁呢?

mvcc和锁操作的数据是同一份吗?

锁住的是Copy出来的版本?或者说已经复制出来一个版本了,就拒绝再复制版本?因为要保证读写不冲突,写写冲突。

undo log、redo log、binlog有什么区别?

redo log为了保证事务的持久化,磁盘io和内存的速率不匹配,通过逻辑物理存储的方式先写到redo log里面,然后再慢慢同步到数据磁盘。
undo log记录的是回滚日志,用于mvcc、事务回滚。
binlog主从复制的日志。
redo log和undo log都是innodb的日志,binlog是mysql本身的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值