mysql进阶之路:mysql中的事务相关知识

1:事务是什么?


事务(Transactional) 就是把多个要做的操作组合成一个整体.利用事务的特性来保证操作的安全性,如果一个事务做到一半出现任何错误,就会进行回滚操作.来恢复成最初的模样.


 2:事务的特性 (具有ACID的特性)


(1) A  原子性(atomicity)  : 事务是一个不可分割的工作单位,事务中的操作要么都修改,要么都不修改。MySql中采用undo Log日志来保证原子性.

(2) C 一致性(consistency):事务在完成时,必须是所有的数据都保持一致状态。 MySql中采用redo Log日志+ undo Log日志 来保证一致性.

(3) I 隔离性(isolation):一个事务的执行不能被其他事务所影响。 MySql中采用锁+MVCC来保证隔离性.

(4) D 持久性(Durability): 持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的. MySql中采用redo Log日志来保证持久性.


3:mysql中的事务使用


mysql中的事务默认是自动提交的,在执行insert,update,delete语句时候每一条sql语句就是一个事务。

3.1 查看事务的提交方式: select @@autocommit; 结果为1表示使用自动提交. 为0表示手动提交

mysql进阶之路:mysql中的事务相关知识_第1张图片

3.2 修改事务的提交方法: set @@autocommit=0;   修改为手动提交

3.3 提交事务的方法:  commit ;  当mysql的事务修改为手动提交的时候,执行完sql会出现数据没有更改的情况, 只有当commit执行后 才会更改数据.

3.4 开启事务的方法: start transaction 或 begin;  事务启动后,所有的sql都会暂时停止修改,只有执行commit才会看到更新后的数据.

3.5 回滚事务的方法: rollback;    

4:并发事务导致的问题

 4.1:脏读

一个事务读取到另外一个事务还没有提交的数据

4.2:不可重复读

一个事务先后读取同一条记录,但两次读取的数据不同

4.3:幻读

一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据后,又发现这行数据已经存在了,像出现了幻觉一样.

5:事务隔离级别

  MySQL 包括的事务隔离级别如下:

  • 读未提交(READ UNCOMITTED)
  • 读提交(READ COMMITTED)
  • 可重复读(REPEATABLE READ) mysql默认使用的
  • 串行化(SERIALIZABLE)

不同隔离级别对应解决的问题

mysql进阶之路:mysql中的事务相关知识_第2张图片5.1:读未提交(READ UNCOMITTED):

    在该隔离级别下,所有事务都可以看到其它未提交事务的执行结果。所以会导致脏读的情况.因为该状态下不加任何锁,性能最好,但安全性最差,所以基本不会使用该级别.

5.2:读提交(READ COMMITTED)

      该隔离级别下,一个事务从开始到提交前所做的任何改变都是不可见的,事务只能读取到已经提交的事务所做的改变。也就是会出现 一个事务执行期间读取到其他事务未提交和已提交的两种不同的数据,所以会出现不可重复读的问题.但是能解决脏读. 

5.3:可重复读(REPEATABLE READ)

      一个事务只能读取到某条记录后,即使其它事务修改了该记录的值并且提交,读到的仍是第一次读到的值,而不是每次都读到不同的数据。那么这种隔离级别就称之为可重复读。是mysql默认的隔离级别.可重复读通过锁+MVCC来减少幻读出现的概率,但不能完全避免幻读的出现.

5.4:串行化(SERIALIZABLE)

       该级别主要通过强制事务排序来解决幻读问题。简单来说,就是在每个读取的数据行上加上共享锁实现,这样就避免了脏读、不可重复读和幻读等问题。但是该事务隔离级别执行效率低下,且性能开销也最大,所以一般情况下不推荐使用。

6:修改事务隔离级别

6.1:查看事务隔离级别的sql:    select @@transaction_isolation;

6.2:当前会话的隔离级别 : set  session  transaction isolation  level     READ UNCOMITTED

6.3:设置全局的隔离级别     set  global transaction isolation  level     READ UNCOMITTED

7:MySql实现ACID的原理

7.1:  A  原子性(atomicity)  

        Mysql 利用Innodb引擎的undo log日志来保证其原子性。 undo log名为回滚日志,是实现原子性的关键,当事务回滚时能够撤销所有已经成功执行的sql语句,他需要记录你要回滚的相应日志信息。其原理是,在你增删改的sql执行时,记录一条相反的sql来保证后续回滚, 

比如:  当你insert一条数据的时候, undo log里面会插入一条删除该数据的sql. undo log记录了这些回滚需要的信息,当事务执行失败或调用了rollback,导致事务需要回滚,便可以利用undo log中的信息将数据回滚到修改之前的样子。

INSERT INTO `test`.`a`(`id`) VALUES (1); //插入一条sql

DELETE FROM `test`.`a` WHERE `id` = 1  //undo log 保存的删除sql

7.2: D 持久性(Durability)

        Mysql 利用Innodb引擎的redo log日志来保证其持久化。如果MySQL宕机,重启时可以读取redo log中的数据,对数据库进行恢复。

        InnoDB作为MySQL的存储引擎,数据是存放在磁盘中的,为了提高性能,InnoDB提供了缓存(Buffer Pool),作为访问数据库的缓冲:当从数据库读取数据时,会首先从Buffer Pool中读取,如果Buffer Pool中没有,则从磁盘读取后放入Buffer Pool;当向数据库写入数据时,会首先写入Buffer Pool,Buffer Pool中修改的数据会定期刷新到磁盘中。然而当当MySQL宕机,而此时Buffer Pool中修改的数据还没有刷新到磁盘,就会导致数据的丢失,事务的持久性无法保证。redo log就是为了防止这种情况,来进行恢复的作用.

7.3  C 一致性(consistency)

          Mysql 利用Innodb引擎的(redo log日志+undo log日志 )组合起来保证其一致性。也就是上面讲过的.一致性是由其他几个特性共同完成所达到的一种特性.

7.4  I 隔离性(isolation)

Mysql 利用Innodb引擎的锁+MVCC来保证其隔离性。

mysql锁的相关知识在我另一篇博客上面查看,本文就讲一下什么是MVCC.

mysql中的锁https://blog.csdn.net/wang5701071/article/details/126170931?spm=1001.2014.3001.5502

8:MVCC(多版本并发控制)

因为比较重要,所以单独进行讲解. 

   mvcc: 全称Multi-Version Concurrency Control,也就是多版本并发控制,是为了在读取数据时提高读取效率和并发性的一种手段。属于一种乐观锁的思路.   指维护一个数据的多个版本,使得读写操作没有冲突,快照读为MySQL实现MVCC提供了一个非阻塞读功能。MVCC的具体实现,还需要依赖于数据库记录中的三个隐式字段、undo log日志、readView。 在这之前还需要了解一下,当前读与快照读.

8.1: 当前读

        读取的是记录的最新版本, 因此读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如下几种方式 都是一种当前读。

select .. lock in share mode(共享锁), 
select ... for update、
update、 insert、 delete(排他锁)

8.2:快照读

        简单的select (不加锁)就是快照读,快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。在不同事务隔离下的当前读        
Read Committed: 每次select, 都生成一个快照读。
Repeatable Read:开启事务后第一个select语句才 是快照读的地方。
Serializable:快照读会退化为当前读。

8.3:数据表中的三个隐藏字段

前两个隐藏字段是每个数据表中都会存在的.

DB_TRX_ID:  最近修改事务ID,记录插入这条记录或最后一-次修改该记录的事务ID。
DB_ ROLL_PTR : 回滚指针,指向这条记录的上一个版本,用于配合undo log,指向.上一个版本。
DB_ROW_ID:    隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段。
 

8.4: undo log 回滚日志

        undo log日志,在insert、 update、delete的时候产生的便于数据回滚的日志。当insert的时候,产生的undo log日志只在回滚时需要,在事务提交后,可被立即删除。而update、delete的时候,产生的undo log日志不仅在回滚时需要,在快照读时也需要,不会立即被删除。所以undo log 不仅是用来保证事务的原子性  还在MVCC中用到了. 在一个操作中,如果有多个事务,在mvcc的控制下会出现一个链表状的历史记录用来存放每一步执行的顺序. 如下图所示,最近执行的事务是DB_TRX_ID最高的4, DB_ ROLL_PTR代表回滚的指针.依次往下指.

mysql进阶之路:mysql中的事务相关知识_第3张图片

  注: 图来源.  B站视频 ​ MySQL数据库入门到精通 ​

8.5:readview (读视图)

ReadView (读视图)是快照读SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的) id。 不同的隔离级别,生成ReadView的时机不同: 通过readview我们才知道自己能够读取哪个版本

readview包含了四个核心的字段.
m_ ids :当前活跃的事务ID集合
rmin_ trx_ jid: 最小活跃事务ID
pmax. tnx_ id :预分配事务ID,当前最大事务ID+1 (因为事务ID是自增的)
creator trx_ id: ReadView创建者的事务ID

mysql进阶之路:mysql中的事务相关知识_第4张图片 注: 图来源.  B站视频 ​ MySQL数据库入门到精通 ​

8.6 mvcc如何实现RC和RR的隔离级别


(1)RC的隔离级别下,每个快照读都会生成并获取最新的readview。

(2)RR的隔离级别下,只有在同一个事务的第一个快照读才会创建readview,之后的每次快照读都使用的同一个readview,所以每次的查询结果都是一样的。

幻读问题
快照读:通过mvcc,RR的隔离级别解决了幻读问题,因为每次使用的都是同一个readview。
当前读:通过next-key锁(行锁+gap锁),RR隔离级别并不能解决幻读问题。

 9:MVCC总结

        MVCC指的就是在使用读已提交(READ COMMITTD)、可重复读(REPEATABLE READ)这两种隔离级别的事务在执行普通的SELECT操作时访问记录的版本链的过程,这样子可以使不同事务的读-写、写-读操作并发执行,从而提升系统性能。

        InnoDB通过为每一行记录添加两个额外的隐藏的值来控制事务的版本,然后通过undo log 版本链找到本次历史事务的版本与指针,然后再readview (读视图)中查看本次的视图是否符合当前事务的版本来实现MVCC

注:  MVCC参考B站视频 ​ MySQL数据库入门到精通 ​

你可能感兴趣的:(Mysql,mysql)