1.并发场景下事务的三种异常现象
数据库允许多个并发事务同时对其数据进行读写和修改的能力,在并发场景下常见以下3种异常现象。
1.1.脏读
脏读表示读取到了事务未提交数据。
比如当一个事务A正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务B也访问这个数据,读了未提交事务操作的数据,然后使用了这个脏数据。
事务B在T5时间点读到的1900元为未提交数据,属于脏读。
1.2.不可重复读
不可重复读指前后多次读取数据不一致。
比如事务B中先后多次读取同一个数据,读取的结果不一样,因为另外一个事务A也访问该同一数据,并且在修改这个数据,这种现象称为不可重复读。
事务B在T3和T6时刻读取到的账户余额不一致,因为T5时刻事务A提交了。
按照正常的事务逻辑
1.2.1.脏读与不可重复读的区别
区别在于:“脏读”读到的是其他事务未提交的数据,“不可重复读”读到的是其他事务已提交的数据。
1.2.2.不可重复读的解决方案
不可重复读是读取了其他事务更改的数据,针对update操作
解决方案:使用行级锁,锁定该行,事务A多次读取操作完成后才释放该锁,这个时候才允许其他事务更改刚才的数据。
1.3.幻读
幻读表示前后多次读取,数据不一致。
在事务A中按照某个条件先后两次查询数据库,两次查询结果的条数不同,这种现象称为幻读。
在T6时刻,事务B读取到的还是2条记录,而实际上已经有3条记录了。
1.3.1.不可重复读与幻读的区别
“不可重复读”是数据变了。
“幻读”是数据的行数变了。
通俗点就是已提交事务A对事务B产生的影响,导致B执行有误,这个影响叫做“幻读”。
1.3.2.幻读解决方案
幻读是读取了其他事务新增的数据,针对insert与delete操作
解决方案:使用表级锁,锁定整张表,事务B多次读取数据总量之后才释放该锁,这个时候才允许其他事务新增数据。
2.事务隔离级别
隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致,解决上面遇到的三个问题。
一般来说,隔离级别越低,系统开销越低,可支持的并发越高,但隔离性也越差。
不同事务的隔离级别,实际上是一致性与并发性的一个权衡与折衷,它本质上也是InnoDB不同的锁策略(Locking Strategy)产生的效果 。
2.1.读未提交(read uncommitted)
Read Uncommitted情况下,可以读取到其他事务还未提交的数据,多次读取结果不一样,出现了脏读、不可重复读的情况。
这是并发最高,一致性最差的隔离级别。
2.2.读提交(read committed)
Read Committed情况下,无法读取到其他事务还未提交的数据,可以读取到其他事务已经提交的数据,多次读取结果不一样,不会出现脏读和幻读,但出现不可重复读。
2.3.可重复读(repeatable read)
可重复读情况下,未出现脏读,未读取到其他事务已提交的数据,多次读取结果一致,即可重复读。但是可能导致“幻读”。
InnoDB默认的隔离级别是repeatable read,互联网用得最多的隔离级别是read committed,它解决了脏读和幻读,保证了数据隔离性和一致性。
2.4.串行化(Serializable)
serializable的隔离级非常严格,在这种串行情况下不存在脏读、不可重复读、幻读的问题了。
如果有未提交的事务正在修改某些行,所有读取这些行的select都会被阻塞住,直到之前的事务执行完成。
这是一致性最好的,但并发性最差的隔离级别。
在大数据量,大并发量的互联网场景下,基本上是不会使用上述这种隔离级别。