首先讲解脏读、幻读、重复读时,我们要知道什么是事务,事务是 就是将一组sql操作封装成一个执行单元,这个执行单元要么一起成功要么一起失败的。
一、Spring 的事务管理分为两种:
- 编程式事务管理:通过编写代码实现的事务管理,包括定义事务的开始、正常执行后的事务提交和异常时的事务回滚。
- 声明式事务管理:建立在 AOP 之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
声明式事务管理不需要入侵代码,并且提供了 @Transactional 注解更为简单、快捷地进行事务操作。
二、脏读、幻读、重复读
- 脏读:指的是读到了其他事务未提交的数据,未提交意味着这些数据可能会回滚,也就是可能最终不会存到数据库中,但是这些数据被读到了,这就是脏读。
- 不可重复读:指的是在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据出现不一致的情况。
- 幻读:指的是事务A在一次查询中得到的结果集中某条数据不存在,此时事务B插入这条数据,事务A去读取这条数据仍然不存在,然后事务A插入这条数据时,却无法插入,也就是事务A第二次读,读到了幻影。
三、事务隔离级别(Isolation)
事务隔离级别指的是若干个并发的事务之间的隔离程度,一般可分为以下五个级别:
- DEFAULT:默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这个值就是READ_COMMITTED。
- READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。
- READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
- REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。
- SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
设置事务的隔离级别可以解决并发事务的问题。
四、如何在Spring中如何使用事务隔离
先在Spring配置中声明式标签,然后声明事务
<tx:advice id="advice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 事务配置
属性:name:对哪些方法起作用,例如:insert* 表示所有以 insert 开头的方法名称。
一般只需要对增、删、改方法添加事务
rollback-for:指定需要进行事务回滚的异常类,默认是 uncheck 异常
其它属性一般默认即可
-->
<tx:method name="insert*" rollback-for="java.lang.Exception"/>
<tx:method name="delete*" rollback-for="java.lang.Exception"/>
<tx:method name="update*" rollback-for="java.lang.Exception"/>
</tx:attributes>
</tx:advice>
配置切面
<aop:config>
<!-- 配置切点表达式 -->
<aop:pointcut id="txPointcut" expression="execution (* service.impl.BankServiceImpl.*(..))"/>
<!-- 将切点和事务的通知整合 -->
<aop:advisor advice-ref="advice" pointcut-ref="txPointcut"/>
</aop:config>