之前我们说过了事务的四个特性(ACID), 不了解的可以点击这里看看 -> Spring事务的四个特性(ACID)
今天来简单说一说隔离级别 …
在操作数据的时候, 一般就会牵扯到数据库事务, 而事务需要满足四个特性, 也就是ACID, 原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation) 和 持久性(Durability).
所谓事务的隔离性,其实事务的这个属性是针对数据库访问的并发性问题而言的。
所谓数据库访问的并发性问题是指多个事务可以同时访问数据库中的数据,而当多个事务在数据库中并发执行(同时执行)时,数据的一致性可能受到破坏,从而导致数据出现问题。
所以隔离性可能带来三个副作用, 分别是 脏读、不可重复读、幻读, 为了避免这 3 个副作用的发生,在标准的 SQL 语句中定义了 4 种隔离级别,分别是未提交读、已提交读、可重复读、可序列化。而在 spring 事务中提供了 5 种隔离级别来对应在 SQL 中定义的 4 种隔离级别,如下:
- ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.另外四个与JDBC的隔离级别相对应
- ISOLATION_READ_UNCOMMITTED: 读未提交
- ISOLATION_READ_COMMITTED: 读提交
- ISOLATION_REPEATABLE_READ: 可重复读
- ISOLATION_SERIALIZABLE: 序列化
1.脏读
所谓脏读就是一个事务 A 读取另一个事务 B 修改但尚未提交的数据, 并在此基础上操作,而事务 B 又执行事务回滚(也就是撤销了事务), 因为这个数据是还没有提交的数据, 那么事务A读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。
2.不可重复读
所谓不可重复读就是一个事务对同一行数据重复读取两次,但是却得到了不同的结果。
在这个事务还没有结束时,另外一个事务也访问该同一数据并进行了修改。 那么,在第一个事务中的两次读此数据之间,由于第二个事务的修改,那么第一个事务两次读到的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
3.幻读
指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中所有数据的某一列进行修改,同时,第二个事务也修改这个表中的数据, 向表中插入一行新数据。那么,第一个事务的用户修改后查询, 发现表中还有没有修改的数据行(第二个事务插入的新数据),就好象发生了幻觉一样。
为了解决以上各种数据库访问的并发性问题(脏读、不可重复读、幻象读),为此数据库提供了4种隔离级别。
1.读未提交(read uncommitted)
事务尚未提交,其他事务即可以看到该事务的修改结果。隔离级别最差,脏读、不可重复读、幻读都不能避免。
2.读提交(read committed)
这是ORACLE默认的隔离级别
事务只能看到其他事务提交之后的数据。可避免脏读,不可重复读、幻读无法避免。
不可重复读原因:A事务修改,B事务查询,A事务提交前和提交后,B事务看到的数据是不一致的。
幻读原因:A事务修改,B事务新增,B事务提交前,A事务已经提交。B事务提交后,A查询发现仍有数据未修改。
3.可重复读(repeatable read)
这是MySQL默认的隔离级别
一个事务多次查询,无论其他事务对数据如何修改,看到的数据都是一致的。因为A事务查询数据时,若B同时在修改数据,A事务看到的永远是B事务执行前的数据。只有当A提交或者回滚之后,看到的才是最新的被B修改之后的数据。可避免脏读、不可重复读,幻读无法避免。
4.序列化(serializable)
事务顺序执行,可避免脏读、不可重复读、幻读,但效率最差。因为A事务执行时,其他事务必须等待。
自上而下, 四种隔离级别由低到高(读未提交最低, 序列化最大), 隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为 Read Committed(读提交)。它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读和丢失更新这些并发性问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。
大多数数据库的默认级别就是 Read committed(授权读取、读提交),比如Sql Server , Oracle。MySQL的默认隔离级别就是 Repeatable read。