脏读
读取未提交数据。脏读即事务A读取到事务B未提交的数据,如果此时事务B数据回滚,事务A仍然是使用旧的数据即是脏的数据。
顺序 | 事务A | 事务B |
---|---|---|
1 | 开始事务 | |
2 | 开始事务 | |
3 | 查询余额2000元 | |
4 | 取出1000元剩余1000元 | |
5 | 查询余额剩余1000元(脏读) | |
6 | 产生异常事务发生回滚,余额剩余2000元 | |
7 | 转入2000元,余额为3000元 | |
8 | 提交事务 | |
- | 数据发生异常(凭空少了1000元) |
不可重复读
前后多次读取,数据内容不一致。事务A多次读取某个数据而这些数据不能保证每次查询都一致。在A的事务期间事务B改变了这个值将导致事务A第二次读取和第一次查询到的值不一致。
顺序 | 事务A | 事务B |
---|---|---|
1 | 开始事务 | |
2 | 第一次查询年龄为20 | |
3 | 开始事务 | |
4 | 其他操作 | |
5 | 更改年龄为30 | |
6 | 提交事务 | |
7 | 第二次查询年龄为30 | |
- | 一个事务中同一条件下第一次查询与第二次查询结果不一致 |
幻读
前后多次读取,数据总量不一致。事务A需要多次根据某固定条件查询统计数据的总量,而这些总量值并不能保证每次查询都一致。在A的事务期间事务B新增数据或删除数据将导致事务A第二次读取和第一次查询到的值不一致。
顺序 | 事务A | 事务B |
---|---|---|
1 | 开始事务 | |
2 | 第一次查询,数据总量为10条 | |
3 | 开始事务 | |
4 | 其他操作 | |
5 | 插入数据2条 | |
6 | 提交事务 | |
7 | 第二次查询数据总量为12条 | |
- | 一个事务中同一条件下查询出的条数不一致 |
事务隔离级别
数据库事务的隔离级别有4种,由低到高分别为Read uncommitted 、Read committed 、Repeatable read 、Serializable 。mysql及oracle的默认事务隔离级别都是REPEATABLE-READ也就是可以重复读。
Read uncommitted
可读取到未提交的数据。在该隔离级别下会发生数据脏读。
Read committed
能够读取已提交的数据。在该隔离级别下虽然不会发生数据脏读但是会发生数据不可重复度。
Repeatable read
能够重复读。在该隔离级别下能够实现数据重复读与避免脏读。对于处于读取状态的行,数据库会对该行进行加锁避免其他事物对该行进行修改。
Serializable
事物串行化。对所有的事务进行串行化有序管理,前一个事务未结束后一个事务不可开始执行。在该事务级别下能避免脏读,不可重复读,幻读。
隔离级别总结
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
Read uncommitted(读未提交) | 可能出现 | 可能出现 | 可能出现 |
Read committed(读已提交) | 不会出现 | 可能出现 | 可能出现 |
Repeatable read(可重复读) | 不会出现 | 不会出现 | 可能出现 |
Serializable(串行化) | 不会出现 | 不会出现 | 不会出现 |
事务传播级别
REQUIRED
查看是否依赖当前事务,如果没有当前事务则自己创建一个新事务,若有当前事务则加入当前事务中。
SUPPORTS
查看是否存在当前事务,如果没有就不开启事务,若有当前事务则加入到当前事务中。
MANDATORY
查看是否存在当前事务,如果没有就直接抛出异常,若存在当前事务则加入到当前事务中。
REQUIRES_NEW
不管是否存在当前事务,如果没有则不管,如果存在则将当前事务挂起,然后自己重新创建一个新的事务。
NOT_SUPPORTED
不管是否存在当前事务,如果没有则不管,如果存在则将当前事务挂起。
NEVER
查看是否存在当前事务,如果存在就直接抛出异常。
NESTED
查看是否存在当前事务,如果没有则按REQUIRED属性执行,若存在当前事务则在当前事务下开启子事务,对于子事务,当父事务准备子事务前会先进行save point打一个标记点,当子事务发生异常回滚时该子事务下所有事务会回到save point点处,当父事务发生异常时候会将包括子事务的数据一起回滚。当父事务无异常提交事务时候也会将子事务数据一起提交。
spring定义
对于五大事务隔离级别及七大事务传播级别Spring在TransactionDefinition接口中定义这些属性
事务隔离级别 | |
---|---|
ISOLATION_DEFAULT | 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别 |
ISOLATION_READ_UNCOMMITTED | 这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读 |
ISOLATION_READ_COMMITTED | 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。 |
ISOLATION_REPEATABLE_READ | 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。 |
ISOLATION_SERIALIZABLE | 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。 |
事务传播级别 | |
---|---|
PROPAGATION_REQUIRED | 如果存在一个事务,则加入当前事务。如果没有事务则开启一个新的事务。 |
PROPAGATION_SUPPORTS | 如果存在一个事务,则加入当前事务。如果没有事务,则非事务的执行。 |
PROPAGATION_MANDATORY | 如果已经存在一个事务,则加入当前事务。如果没有一个活动的事务,则抛出异常。 |
PROPAGATION_REQUIRES_NEW | 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。 |
PROPAGATION_NOT_SUPPORTED | 总是非事务地执行,并挂起任何存在的事务。 |
PROPAGATION_NEVER | 总是非事务地执行,如果存在一个活动事务,则抛出异常。 |
PROPAGATION_NESTED | 如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行 |