并发事务带来的问题
脏读:读取到其他事务修改的未提交的被回滚的数据
幻读:因为其他并发事务新增了数据,导致一个事务内重复查询结果不一致。
不可重复读:因为其他并发事务修改了数据,导致一个事务内重复查询结果不一致。
①脏读:事务1对数据age=20进行了读取并修改age=21(前提:即使数据未提交,其他事务也可以读取到修改后的数据),但还未提交事务,事务2对数据进行了读取,读取到age=21,这时事务1因为某些原因回滚了,于是age又恢复为20,事务2再来读取,读取到age=20。事务2中间读取到的age=21就是脏数据。
②不可重复读:事务1读取age=20,事务2读取age=20,事务1修改了age=19,事务2再次读取age=19,这就造成了事务2在一个事务内两次读取同一份数据结果不一致,称为不可重复读。
③幻读:一个事务查询了几行数据,另一个事务并发的插入一些数据,在第一个事务随后的查询中,发现多出了一些数据,就好像出现了幻觉一样,称为幻读。比如,事务1查询表记录数,即count(*),但事务2并发的插入了一些数据,事务1再次执行count(*)时,结果就多了一些。
不可重复读和幻读其实很相似,只是不可重复读的侧重点在于数据被修改了导致重复查询结果不一致,而幻读侧重于数据变多了导致重复查询结果不一致。
幻读其实可以看作不可重复读的一种特殊情况,但是因为两种问题的解决方案不一样,所以单独把幻读分出来了。
对update、delete操作,导致的不可重复读,可以直接在记录行加锁解决,但对于insert操作,导致的幻读,因为是新增,行锁只能对已存在的记录加锁,所以要用临键锁(间隙锁+行锁)解决。
四种隔离级别
SQL标准定义了四个隔离级别:
READ-UNCOMMITTED(读未提交):最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。(能读取到未提交的数据,有事务在修改数据,一个事务去读取那个数据就可能读到要被回滚的脏数据)
READ-COMMITTED(读已提交):允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。(不会读取到未提交的数据,就阻止了脏读。但是如果事务1读取了数据,事务2对数据进行了修改并提交了事务,事务1又再次读取了这条数据,就读取到修改后的数据,就会出现在事务1一个事务内重复读取同一个数据出现数据不一致的情况,导致不可重复读。幻读同理)
REPEATABLE-READ(可重复读):对同一字段的多次读取结果都是一致的,除非数据是被事务本身所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。(事务1查询范围内数据,事务2在这个范围内插入了一些新数据,事务1再次查询,发现多出了数据或者查到的数据不一致了,幻读)
SERIALIZABLE(可串行化):最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰。该级别可以防止脏读、不可重复读以及幻读。