前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Mysql关于锁方面和事务方面的问题

Mysql关于锁方面和事务方面的问题

作者头像
名字是乱打的
发布2022-05-13 10:45:34
5800
发布2022-05-13 10:45:34
举报
文章被收录于专栏:软件工程
常见问题
  • 一 MyISAM与InnoDB关于锁方面的区别是什么
  • 二 数据库事务的四大特性
  • 三 事务隔离级别以及各级别下的并发访问问题
  • 四 InnoDB可重复读隔离级别下如何避免幻读
  • 五 RC、RR级别下的InnoDB的非阻塞读如何实现
一 MyISAM与InnoDB关于锁方面的区别是什么
  • MyISAM默认用的是表级锁,不支持行级锁 它会锁主整张表(其中读锁是共享锁,写锁是排他锁)
  • InnoDB默认用的是行级锁,也支持表级锁
二 数据库事务的四大特性ACID
  • 原子性(Atomic) 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚
  • 一致性(Consistency) 一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
  • 隔离性(Isolation) 隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
  • 持久性(Durability) 持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
三 事务特性的实现大概原理
  • 原子性: 语句要么都执行,要么都不是执行,是事务最核心的特性,事务本身来说就是以原子性历来定义的,实现主要是基于undo log
  • 持久性: 保证事务提交之后,不会因为宕机等其他的原因而导致数据的丢失,主要是基于 redo log实现
  • 隔离性: 是通过锁机制实现的。当一个事务需要对数据库中的某行数据进行修改时,需要先给数据加锁。加了锁的数据,其它事务是不运行操作的,只能等待当前事务提交或回滚将锁释放。
  • 一致性: 事务追求的最终目标,ACID里的AID都是数据库的特征,这个C(一致),实际上它依赖于应用层,也就是依赖于开发者。这里的一致性是指系统从一个正确的状态,迁移到另一个正确的状态。什么叫正确的状态呢?就是当前的状态满足预定的约束就叫做正确的状态。而事务具备ACID里C的特性是说通过事务的AID来保证我们的一致性。

四 事务隔离级别以及各级别下的并发访问问题

数据库隔离级别的查看和设置!
并发访问可能出现的问题

现在来看看MySQL数据库为我们提供的四种隔离级别:  ① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。  ② Repeatable read (可重复读):可避免脏读、不可重复读的发生。  ③ Read committed (读已提交):可避免脏读的发生.     ④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。 事务隔离级别对应可以规避的问题

五 InnoDB可重复读隔离级别下如何避免幻读

开启间隙锁, 间隙锁会封锁该条记录相邻两个键之间的空白区域,防止其它事务在这个区域内插入、修改、删除数据;所谓间隙是将数据分为不同区间,对该区间范围进行加锁,区间的规则为左开右闭,比如当数据为1,3,5时,对应的区间为(-∞,1],(1,3],(3,5],(5,+∞];

他这个行锁+间隙锁就组成了next—key lock(Next-Key Locks,就是Record lock和gap lock的结合,即除了锁住记录本身,还要再锁住索引之间的间隙。),innodb在可重复度隔离级别下,采用next-key lock来防止幻读,因此实现了最高的隔离级别。

五 RC(读已提交)、RR(可重复读)级别下的InnoDB的非阻塞读如何实现
5.1 RR(可重复读)级别下的InnoDB的(快照读)非阻塞读是如何实现的?

底层实现离不开数据行里的DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID字段,除此之外还需要undo日志,以及read view。

原理实现就是下列几个关键内容:

  • 数据行里的DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID
  • undo日志
  • read view机制

说起DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID,那就要先知道MySQL一条记录是由记录的额外信息部分和记录的真实数据两部分组成。记录的额外记录部分存有变长字段长度列表、NULL值列表等,而记录的真实数据部分又由真实数据以及DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID这三个隐藏列组成。

比如现在有一个记录Field1、Field2、Field3数据分别为11、12、13,现在事务要修改该记录,将Field2修改为32。则这条记录首先会加载X锁,首先undo log中会拷贝一条修改前的记录,并赋值DB_ROW_ID。此时被X锁锁住的记录的DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID分别进行赋值,并且DB_ROLL_PTR的记录会指向undo log中的DB_ROW_ID的值。

如果此时又有一个事务对该记录进行了修改,则undo log日志中又会增加一条日志。

这样就是快照读版本的实现了。

5.2 InnoDB如何在RR隔离界别下避免幻读——next-key锁

其实,真正实现RR隔离级别下的幻读现象,是由next-key锁解决的。next-key锁又分为了(行锁 + gap锁)

5.2.1行锁 行锁就是Record Lock,就是对单个行记录加的锁。X锁和S锁就是行锁。

5.2.2 Gap锁 Gap就是索引树种,插入新数据的间隙。间隙锁即锁定一个记录的范围,但是不锁定记录本身。间隙锁是为了避免同一事务的两次当前读出现幻读的情况。需要注意的是,Gap锁在RU、RC隔离级别下时不存在的,在RR、Serializable隔离级别下都只支持Gap锁。这就是为什么RU、RC隔离级别下无法避免幻读,RR、Serializable能够避免幻读的原因。

下面讨论的都是在RR隔离级别下出现Gap锁的场景。

代码语言:javascript
复制
  1.在RR隔离级别下,无论删、改、查,当前读若用到主键索引或者唯一键索引,会使用Gap锁吗?
答:如果where条件全部命中,则不会用Gap锁,只会加记录锁。

怎么去理解where条件全部命中,不用加Gap锁只需要加记录锁就行了呢?这是因为比如A事务需要修改操作所有记录,此时B事务使用主键索引id来进行where条件查询来进行删除操作,此时只需要锁住where命中的id记录即可,那么就能防止事务A出现幻读现象。

如图,tb中name为主键索引,id为唯一索引。某个事务使用delete from tb where id = 9进行删除操作,首先where条件全部命中,所以先会为id为9的这个记录的唯一索引加上行锁,然后会为name为d的主键索引(聚镞索引)加上排他锁。这是为了防止其他事务对where name = 9进行操作,导致数据不一致的情况。

代码语言:javascript
复制
2.在RR隔离级别下,无论删、改、查,当前读若用到主键索引或者唯一键索引,且如果where条件部分命中
或者全不命中,则会加Gap锁。对于这种情况,就包含了范围查询以及精确查询非全部命中的情况。
例子1:比如现在事务A要删除一条不存在的id为7的记录,此时事务B要新增一条id为8的记录,会发现事务B一直
处于等待中,这是因为精准查询全部都不命中,会对该记录范围加Gap锁。

例子2:【tb_student中存在id为5,6,9的学生】比如在事务A中使用语句select * from tb_student where id in (5,7,9) lock in share mode;使用当前读(共享锁)来查询学生信息。在另外一个事务B中去进行新增id为6,7,8的学生,发现事务一直在等待中。这里是因为where id in (5,7,9)部分命中,所以会为(5,9]加Gap锁,锁的范围为左开右闭。因此事务B新增id为7,8的记录会被Gap锁锁住,这就是精准查询不全部命中的情况。

代码语言:javascript
复制
3.Gao锁会用在非唯一索引或者不走索引的当前读中
非唯一索引

比如图中某一事务A执行delete from tb1 where id = 9,因为id是非唯一索引,如果没有加Gap锁,在事务B新增一条id为9的记录时,A事务执行完delete语句后,就会发现成功删除3条记录,出现了幻觉,所以给id为9的记录加上Gap锁来防止幻读的发生。 至于Gap锁的范围,如上为:(-∞,2], (2, 6], (6, 9], (9, 11], (11, 15], (15, +∞)中的 (6, 9], (9, 11]

不走索引

对于不走索引的情况,InnoDB会为所有的Gap加锁,相当于锁表。

四、总结

4.1 InnoDB在RR隔离级别下是如何实现幻读问题的解决的呢?

表象:快照读(非阻塞读),伪MVCC 底层:next-key(行锁+Gap锁) a. 在RU、RC隔离级别下不存在Gap锁,所以在RU、RC隔离级别下无法解决幻读;在RR、Serializable隔离级别下都实现了Gap锁,所以解决了幻读现象。 b. 在RR隔离级别下,如果删、改、查语句的where条件走的是主键索引或者唯一索引 i. where条件全部命中,则给该记录加上记录锁。 ii. where条件不全部命中,则给该记录周围加上Gap锁。 iii. 加上记录锁或者是Gap锁都是为了防止RR隔离级别下发生幻读现象。 c. 在RR隔离级别下,如果删、改、查语句的where条件没有走索引或者是非唯一索引或非主键索引 在当前读where条件如果没有走非唯一索引或者没有走索引,则会使用Gap锁锁住当前记录的Gap,防止幻读的发生

4.2 InnoDB中非阻塞读(快照读)底层是怎么实现的?

记录中存储的隐藏列DB_TRX_ID、DB_ROW_ID、DB_ROLL_ID undo日志根据上述隐藏列来进行记录数据回滚(版本回滚) review机制

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 常见问题
  • 一 MyISAM与InnoDB关于锁方面的区别是什么
  • 二 数据库事务的四大特性ACID
  • 三 事务特性的实现大概原理
    • 并发访问可能出现的问题
    • 五 InnoDB可重复读隔离级别下如何避免幻读
    • 五 RC(读已提交)、RR(可重复读)级别下的InnoDB的非阻塞读如何实现
      • 5.1 RR(可重复读)级别下的InnoDB的(快照读)非阻塞读是如何实现的?
        • 5.2 InnoDB如何在RR隔离界别下避免幻读——next-key锁
        • 四、总结
          • 4.1 InnoDB在RR隔离级别下是如何实现幻读问题的解决的呢?
            • 4.2 InnoDB中非阻塞读(快照读)底层是怎么实现的?
            相关产品与服务
            云数据库 SQL Server
            腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档