事务(Transaction):
事务的四个属性:
原子性(Atomicity):同一个事务下,事务是不可被分割的
一致性(Consistency):一致性,事务的的前后数据的完整性需一致
隔离性(Isolation):不同事务之间相互隔离,互不影响
持久性(Durability):事务一旦执行,数据库的变化就是永久性的
以上原子性,隔离性,持久性都是为了数据的一致性服务
事务的隔离级别
读未提交 | 读已提交 | 可重复读 | 串行化 | |
脏读 | √ | X | X | X |
不可重复读 | √ | √ | X | X |
幻读 | √ | √ | √ | X |
脏读:一个事务还未提交的时候,另一个事务读到了该事务中未提交的数据
不可重复读:同一个事务中,两次读取的结果,由于其他事务的提交,导致读取结果不一致
幻读:事务A进行某条件下的数据变更操作,事务B对相同搜索条件的数据发生了数据新增的操作,导致事务A提交以后仿佛发生了"诡异",有数据没有被修改
不可重复读与幻读的区别:
不可重复读,是同一个事务中,两次读取操作导致数据不一致,幻读指的是事务不是独立执行时发生的一种现象,例如,第一个事务对全部数据做修改,第二个事务在第一个事务执行期间,新增了数据,当第一个事务提交以后发现有数据没有被修改,如同发生了幻觉
MVCC(Multi-Version Concurrency Control)多版本并发控制
- 什么是MVCC
多版本指的是每一条记录都会有多个版本,每次修改记录之前都会存储该记录的版本,从而形成多个版本构成的链.这样不同时间启动的事务可以无锁的读取版本的数据.读写不会被阻塞,写也不会有影响只要行程版本链即刻.而已经启动的事务也可以读取以及存储的历史版本.
- 什么是当前读和快照读
当前读: 共享锁(S),独占锁(X)都是当前读,他们读取的是记录的最新版本,且读取的时候为了防止其他并发事务修改记录,要加锁
快照读: 不加锁的读取操作就是快照读,且不能是串行隔离级别下的读取。基于MVCC,快照读读取的记录可能不是最新数据,可能是记录的历史版本
- 当前读,快照都和MVCC的关系
虽然MVCC的目的是为了实现维持记录的多个版本,使读写不会发生冲突,但实际过程中,mysql需要提供具体的功能,而快照读就是MVCC中的一个非阻塞读取功能呢,也是一种悲观锁的实现。而快照读本身也是以恶搞抽象概念,具体实现是通过MVCC在MySQL实现的过程中通过一些隐藏字段,unlog日志,ReadView来实现
- MVCC实现了哪几个隔离级别,解决了什么问题,有什么好处
在四种隔离级别中,首先串行化是不需要其他帮忙解决的,因为串行化每一次操作执行都是串行执行的。而读未提交,只要读取保证读取的是最新记录就好了。
数据库的三个并发场景
读-读: 不存在问题,不需要考虑并发
读-写:有线程问题,可能造成事务的隔离性问题,可能会导致脏读,不可重复读,幻读
写-写:有线程问题,可能存在数据丢失问题
好处:MVCC主要用于解决读写冲突的无锁并发问题,每一个修改都会保存一个版本,而版本和事务时间戳关联,读操作只读该事务开始之前的数据库快照。
并发操作时,可以做到读操作时,不用阻塞写操作,写操作有而不会阻塞读操作。提高了并发读写的性能
可以解决脏读,不可重复读,幻读,但是无法解决数据丢失的更新问题
当MVCC与锁进行结合,MVCC负责解决读写重读,悲观锁或乐观锁解决写写冲突
- 为什么需要MVCC,没有MVCC会怎么样
当事务A正在执行,而事务B修改了同一个记录,还未提交。如果事务A要读取记录,因为事务B未提交,所以事务A无法读取最新的记录,因为一旦读取,就是脏读。所以读取记录的时候只能读取事务B执行修改之前的记录。但数据已经被事务B修改,事务A只能阻塞事务B的提交。
多版本情况下,事务B修改数据之前会生产历史版本,事务A就可以读取之前的数据记录。读写就不会阻塞