事务原则->ACID:原子性、一致性、隔离性、持久性。
那么,如何去保证原子性和持久性?
> undo log(回滚日志)实现了事务的原子性。在MySQL数据库InnoDB存储引擎中,还用undo log来实现多版本并发控制(MVCC);
> redo log(重做日志)保证了事务的持久性。
而,隔离性本质上通过锁来实现。MySQL中有三种行锁算法,Record Lock(单行锁定),Gap Lock(间隙锁)和Next-Key Locking(Record+Gap)。
事务并发产生的问题
脏读:原数据为Y,A事务改为A1未提交,B事务读到A1。B事务读取了A事务未提交的数据。
不可重复读:原数据为Y,A事务改为A1未提交,B读到Y;A事务提交后,B读到A1。B事务多次读取结果不同。
幻读:一般是行影响,B事务读取到了A事务插入的数据,导致前后不一致。
隔离级别
脏读 | 不可重复读 | 幻读 | |
读未提交(read-uncommitted) | √ | √ | √ |
读已提交(read-committed) | × | √ | √ |
可重复读(repeatable-read) | × | × | √ (对于innoDB ×) |
可串行化(serializable) | × | × | × |
1、读未提交:未对行进行加锁,其他事务可以访问。
2、读已提交:采用一致性非锁定读模式,即若此行正被其他事务锁定,那么通过MVCC技术,当前事务可以读取此行的一个最近提交的快照数据。
3、可重复读:MySQL的默认隔离级别;采用一致性非锁定读模式,通过MVCC,在读取某行数据时,如果此行被其他事务锁定,则当前事务不用阻塞,直接读取当前事务开始时的此行的一个数据快照,来解决不可重复读问题;另通过Next-Key Locking锁定一个范围,使范围内的数据不能同时在其他事务中插入,避免了当前事务出现“幻行”问题。可重复读已经达到了SQL标准的Serializable标准,即(无脏读,可重复读MVCC,无幻读Next-Key Locking)。
4、可串行化:串行化执行事务;不支持一致性非锁定读。
tips
两种读取数据的模式:一致性锁定读和一致性非锁定读。
1、一致性锁定读:显式的对数据进行加锁以保证数据逻辑的一致性。对于SELECT语句支持两种一致性读:
> SELECT…FOR UPDATE,对读取事务加X锁(排他锁)
> SELECT…LOCK IN SHARE MODE,对读取事务加S锁(共享锁)
2、一致性非锁定读:当事务读取的某行数据被其他事务锁定时,可以不用等待锁释放,而是读取此行的一个具有一致性的数据快照,而这个快照数据就存储在undo日志中,即通过MVCC(一行数据有多个版本)实现。
MVCC(多版本并发控制)是一个通用概念,有多种实现方式,MySQL是通过undo日志来实现的。