MySQL~事务的四大特性和隔离级别

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

事务的四大特性

1.原子性一个事务transaction中的所有操作要么全部完成要么全部不完成。事务在执行过程中发生错误会被回滚Rollback到事务开始前的状态就像这个事务从来没有执行过一样通过undo log实现。

2.持久性事务处理结束后数据库会把对数据的修改写到磁盘上即便系统故障也不会丢失保证了数据的持久性通过redo logo来保证。

3.隔离性数据库允许多个并发事务同时对其数据进行读写和修改的能力隔离性可以让不同的事务看到不同的数据内容防止多个事务并发执行导致数据不一致的问题。通过MVCC多版本并发控制实现用到了ReadView读视图和undo log里面的历史版本链。

4.一致性指事务操作前后是从一个一致性的状态到另一个一致性的状态它是由原子性持久性隔离性来共同保证一致性的。

  • 原子性保证一致性比如说银行转账一方扣钱一方加钱两条SQL属于一个事务为了保证双方金额的一致性两条SQL必须同时执行成功或者就都不执行这就保证了前后数据的一致性。
  • 持久性保证一致性比如我买了一个月以后回家的飞机票一个月后买票的数据没了但是我钱也花了这就导致了数据的不一致。数据库要保证一个月后我买票的数据还在就是通过持久性来保证的。把买票的数据保存到磁盘上去
  • 隔离性保证一致性如果没有隔离性一致性同样得不到保证。比如在统计考试成绩的时候一个事务里面两条SQL一条统计所有科目的平均分一条统计语数英三门课的平均分。如果没有隔离性一开始数学是60分平均分统计完后数学被其他事务改成了100分后一条统计语数英三门课的平均分的时候使用的数学成绩就和之前的不一样了这就导致了不一致性。所以需要隔离性来保证事务的一致性。

事务的隔离级别

事务并行时会出现的问题

脏读一个事务读取到了另一个事物修改后但是还没有提交的数据这就发生了脏读。此时如果你发生回滚那我读到的就是过期的数据。

不可重复读在一个事务内多次读取同一个数据发现读取到的数据不一样就发生了不可重复读的情况。事务A第一次读的是时候是100然后事务B把这个值修改成了200然后提交事务A再读的时候就变成200了重复读数据但是读到的却是不同的值。

幻读一个事务内多次统计符合某个条件的记录数量发现前后统计的数量不一致。比如事务A一开始统计不及格的人数有3个然后事务B插入了一个不及格的人员信息提交了事务此时事务A再查不及格的记录数就变成4个了。

隔离级别

  • 读未提交read uncommitted指一个事务还没提交时它做的修改就能被其他事务看到
  • 读提交read committed指一个事务提交之后它做的修改才能被其他事务看到
  • 可重复读repeatable read指一个事务执行过程中看到的数据一直跟这个事务启动时看到的数据是一致的我可以重复读不会读取到不一样的数据。MySQL InnoDB 引擎的默认隔离级别
  • 串行化serializable 会对记录加上读写锁在多个事务对这条记录进行读写操作时如果发生了读写冲突的时候后访问的事务必须等前一个事务执行完成才能继续执行

隔离级别越高越不容易出问题但是相对的效率也会更低。

  • 在「读未提交」隔离级别下可能发生脏读、不可重复读和幻读现象
  • 在「读提交」隔离级别下可能发生不可重复读和幻读现象但是不可能发生脏读现象
  • 在「可重复读」隔离级别下可能发生幻读现象但是不可能脏读和不可重复读现象
  • 在「串行化」隔离级别下脏读、不可重复读和幻读现象都不可能会发生。

如何实现隔离级别

  • 读未提交要读取到未提交的修改数据所以直接读最新的数据就行
  • 串行化通过加锁的方式实现
  • 读提交和可重复读通过MVCC多版本并发控制来实现的用到了Undo log里面的历史版本链还有ReadView读快照。PS准确一点还用到了几个隐藏字段通过隐藏字段访问到历史版本链和最近修改记录的事务ID

        可重复读的是每次事务启动都生成一个ReadView后续整个事务就使用这个ReadView。而读提交是每次读取数据的时候会重新生成一个ReadView。

ReadView中有4个字段

  • create_transaction_id指创建该ReadView的事务id
  • m_ids当前活跃且未提交的事务列表
  • min_transaction_id当前活跃且未提交的事务列表中事务id的最小值
  • max_transaction_id创建ReadView时当前数据库中要分配给下一个事务的id。

然后每条记录里面还有两个隐藏字段

  • transaction_id表示最近一次修改该记录的事务id
  • roll_pointer指针指向undo log里面该记录的历史版本链记录该记录被修改的不同版本用链表的形式连接起来。

开始

 

        当一个事务访问该记录的时候首先获取最近修改该记录的事务id就是transaction_id字段然后获取到undo log历史版本链中的最新版本。

  1. 如果是自身那当然允许访问
  2. 如果小于min_transaction_id表示该版本在创建ReadView之前就创建了固然允许访问。
  3. 如果大于max_transaction_id表示该版本是在创建了ReadView之后才生成的固然不允许访问跳转到下一个历史版本
  4. 如果在min_transaction_id和max_transaction_id之间则需要判断当前修改过该记录的事务有没有提交提交了就可以访问没有提交就不能访问。

        可以查看transaction_id是否在m_ids列表中如果在说明该事务还在活跃没有提交就不能访问该版本如果不在说明该事务已经提交固可以访问。

        就经过这样一个过程最终会找到当前事务可以访问的那个版本来访问。

 

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: mysql