Mysql事务原理与优化最佳实践

圣辉 / 2024-04-29 / 原文

学习来源-图灵课堂

https://vip.tulingxueyuan.cn

说到MySQL的innodb的一大特性,就不得不说到事务。今天就学习事务。

事务

事务的定义:逻辑上的一组操作,要么一起成功,要么一起失败,中间绝对不会存在别的状态。逻辑上的一组操作,就是说这些操作都是有逻辑关系的。

我们通常说的事务是针对修改操作(新增,编辑,删除),但是查询操作也是可以加事务的。

事务有四大特性:ACID,就是所谓的原子性,一致性,隔离性,持久性。其中一致性是其它三个特性都满足之后才能实现的。

  1. 原子性(Atomicity) :当前事务的操作要么同时成功,要么同时失败,从效果上看一体的。原子性由undo log日志来实现。针对修改操作,undo log中会写入和其完全相反的一句SQL,便于rollback;rollback和commit是保证原子性的。
  2. 一致性(Consistent) :使用事务的最终目的,由其它3个特性以及业务代码正确逻辑来实现。
  3. 隔离性(Isolation) :在事务并发执行时,他们内部的操作不能互相干扰。隔离性由MySQL的各种锁以及MVCC机制来实现。
  4. 持久性(Durable) :一旦提交了事务,它对数据库的改变就应该是永久性的。持久性由redo log日志来实现。

并发事务带来的问题

  • 更新丢失(Lost Update)或脏写:当两个或多个事务选择同一行数据修改,有可能发生更新丢失问题,即最后的更新覆盖了由其他事务所做的更新。
  • 脏读(Dirty Reads):事务A读取到了事务B已经修改但尚未提交的数据,回滚之后数据无效。
  • 不可重读(Non-Repeatable Reads):事务A内部的相同查询语句在不同时刻读出的结果不一致。主要是针对查询单条数据,别的事务可能对这行数据进行了修改。
  • 幻读(Phantom Reads)或者是幻读:事务A读取到了事务B提交的新增数据。主要是读期间别的事务执行了插入操作。每次读取都能得到新的数据。

事务隔离级别

事务隔离级别是数据库本身提供的功能。都有其默认值,但是也可以进行修改的。可以根据业务需求去决定是否要修改默认的隔离级别。
隔离级别

脏读(Dirty Read)

不可重复读

幻读(Phantom Read)
读未提交(Read
uncommitted)
可能   可能  可能
读已提交(Read
committed)
不可能 可能 可能
可重复读
(Repeatable read) 
不可能 不可能 可能
可串行化
(Serializable) 
不可能 不可能 不可能
 
 
 
 
 
 
 
 
事务隔离级别越高,其安全性一致性就越好,但是相应的其执行效率就越低。
不同的业务场景针对事务隔离级别有要求,可以针对的进行设置。
MySQL默认的隔离级别是可重复读;Oracle默认的隔离级别是读已提交。
用Spring开发程序时,如果不设置隔离级别默认用数据库设置的隔离级别,如果Spring设置了就用已经设置的隔离级别。
 

事务隔离级别的具体实现

  • 读未提交,没有进行任何额外处理,其数据库执行效率是最高的,但是其数据库安全性是最低的, 要在业务侧保证事务的执行。
  • 读已提交,此时是读的当前,当前读就是时刻读取当前的最新已经提交的值。
  • 可重复读,引入了MVCC和锁机制去保证。其中MVCC就用到了快照读,就是读的历史版本;锁机制,提高间隙锁等。
  • 可串行化,是严格的加锁机制,读写互斥,写写互斥,读读不互斥。是类似Java的悲观锁。效率极其低下。
 
 
 
 
 
 
 
 
 
 
 

 

真实的数据只是会维护一份;不同线程的查询是通过整个版本链来查的。所有的查询修改共同构成这条数据的版本链。

每次数据的修改,都会有自己的一套版本链。查询的时候,就是通过可见性算法去定位到自己要查询的版本。

并不是多个快照,多个日志,多条真实数据;这样的话就太占用空间了。