事务ACID
原子性
一致性
持久性
隔离性

《MySQL技术内幕》7.1.2
事务实现
事务隔离性由第6章讲述的锁来实现。原子性、一致性、持久性通过数据库的redolog和undo log来完成。redo log称为重做日志,用来保证事务的原子性和持久性。undo log用来保证事务的一致性。
《MySQL技术内幕》7.2
原子性、一致性、持久性实现
参考
[
](https://www.processon.com/view/link/61d052c8e0b34d1be79b532d)
隔离性实现
当多个事务操作数据库数据时,就会存在一系列并发问题:[2,5]
数据丢失
脏读:读到了其他事务未提交的数据 (在ru下会出现)
不可重复读
幻读; 
需要通过事务隔离机制来解决:
读未提交:一个事务还没提交时,它做的变更就能被别的事务看到
读已提交:一个事务提交之后,它做的变更才会被其他事务看到
可重复读:一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。
串行化:对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。
|
| 脏读 | 不可重复读 | 幻读 | |
|---|---|---|---|
| READ-UNCOMMITTED | √ | √ | √ |
| READ-COMMITTED | × | √ | √ |
| REPEATABLE-READ | × | × | √ |
| SERIALIZABLE | × | × | × |
(在InnoDB中,在REPEATABLE-READ中使用Next-Key Lock)
而事务隔离可以通过锁机制来实现的。
共享锁(S)和排他锁(X)。共享锁允许一个事务读数据,不允许修改数据,如果其他事务要再对该行加锁,只能加共享锁;排他锁是修改数据时加的锁,可以读取和修改数据,一旦一个事务对该行数据加锁,其他事务将不能再对该数据加任务锁
未提交读(Read Uncommitted):在事务 A 读取数据时,事务 B 读取数据加了共享锁,修改数据时加了排它锁。这种隔离级别,会导致脏读、不可重复读以及幻读。
已提交读(Read Committed):在事务 A 读取数据时增加了共享锁,一旦读取,立即释放锁,事务 B 读取修改数据时增加了行级排他锁,直到事务结束才释放锁。也就是说,事务 A 在读取数据时,事务 B 只能读取数据,不能修改。当事务 A 读取到数据后,事务 B 才能修改。这种隔离级别,可以避免脏读,但依然存在不可重复读以及幻读的问题。(不可重复读:当事务A第二次读数据时,读到的可能是B修改后的数据)
可重复读(Repeatable Read):在事务 A 读取数据时增加了共享锁,事务结束,才释放锁,事务 B 读取修改数据时增加了行级排他锁,直到事务结束才释放锁。也就是说,事务 A 在没有结束事务时,事务 B 只能读取数据,不能修改。当事务 A 结束事务,事务 B 才能修改。这种隔离级别,可以避免脏读、不可重复读,但依然存在幻读的问题。(幻读:A在事务过程中,添加了一两行记录时,B可能)
可序列化(Serializable):在事务 A 读取数据时增加了共享锁,事务结束,才释放锁,事务 B 读取修改数据时增加了表级排他锁,直到事务结束才释放锁。可序列化解决了脏读、不可重复读、幻读等问题,但隔离级别越来越高的同时,并发性会越来越低。
但这种通过锁方式实现的事务,性能不高(一旦数据被加上排他锁,其他事务将无法加入共享锁,且处于阻塞等待状态,如果一张表有大量的请求,这样的性能将是无法支持的。)
InnoDB 中的 RC 和 RR 隔离事务是基于多版本并发控制(MVCC)实现高性能事务。
MVCC 对普通的 Select 不加锁,如果读取的数据正在执行 Delete 或 Update 操作,这时读取操作不会等待排它锁的释放,而是直接利用 MVCC 读取该行的数据快照(数据快照是指在该行的之前版本的数据,而数据快照的版本是基于 undo 实现的,undo 是用来做事务回滚的,记录了回滚的不同版本的行记录)。MVCC 避免了对数据重复加锁的过程,大大提高了读操作的性能。
参考
1、04-事务-JavaGuide
2、34 | MySQL调优之事务:高并发场景下的数据库事务调优-极客时间
3、03 | 事务隔离:为什么你改了我还看不见?-极客时间
4、04-事务|Innodb中的事务隔离级别和锁的关系 - 美团技术团队
5、15丨初识事务隔离:隔离的级别有哪些,它们都解决了哪些异常问题?
6、23 | MySQL是怎么保证数据不丢的?-极客时间
7、MySQL 的 crash-safe 原理解析
8、更新SQL执行过程
9、31丨为什么大部分RDBMS都会支持MVCC?



