文章目录
1. 事务
1.1 事务的特性
事务具有ACID四个特性:
原子性(Atomicity):事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生
一致性(Consistency):事务在完成后数据的完整性必须保持一致
隔离性(Isolation):多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间的数据要相互隔离
持久性(Durability):一个事务一旦被提交,它对数据库中数据的改变应该是永久性的,即使数据库发生故障也不应该对其有任何影响
如果整个事务执行过程中,有任何一个地方出现异常/错误,那么都会进行事务回滚,回滚之后数据的状态将和事务执行之前完全一致。
1.2 事务隔离级别
隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义有五个表示隔离级别的常量:
TransactionDefinition 接口事务隔离级别 | 描述 |
---|---|
ISOLATION_DEFAULT | 默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED |
ISOLATION_READ_UNCOMMITTED | 该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。 |
ISOLATION_READ_COMMITTED | 该隔离级别表示一个事务只能读取另一个事务已经提交的数据。可以防止脏读,是大多数情况下的推荐值。 |
ISOLATION_REPEATABLE_READ | 该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。 |
ISOLATION_SERIALIZABLE | 所有的事务依次逐个执行,事务之间就完全不可能产生干扰。该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。 |
1.3 事务的传播特性
事务传播特性:如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。
TransactionDefinition中定义中这些表示传播行为的常量
TransactionDefinition事务传播行为常量 | 描述 |
---|---|
PROPAGATION_REQUIRED | 默认值。如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务 |
PROPAGATION_REQUIRES_NEW | 创建一个新的事务,如果当前存在事务,则把当前事务挂起 |
PROPAGATION_SUPPORTS | 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式运行,如果当前存在事务,则把当前事务挂起。 |
PROPAGATION_NEVER | 以非事务方式运行,如果当前存在事务,则抛出异常。 |
PROPAGATION_MANDATORY | 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。 |
PROPAGATION_NESTED | 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。 |
1.4 事务的回滚规则
默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚。可以明确的配置在抛出哪些异常时回滚事务,包括checked异常。也可以明确定义那些异常抛出时不回滚事务。还可以编程性的通过setRollbackOnly()方法来指示一个事务必须回滚,在调用完setRollbackOnly()后你所能执行的唯一操作就是回滚。
2. Spring事务管理
Spring事务管理分为编程式事务管理和声明式事务管理
2.1 声明式事务管理
声明式事务是建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
声明式事务管理最大的优点是不需要通过编程的方式管理事务,因而不需要在业务逻辑代码中掺杂事务处理的代码,只需相关的事务规则声明,便可以将事务规则应用到业务逻辑中
//如果不想某个异常进行事务处理
@Transactional(rollbackFor=RuntimeException.class)//不对RuntimeException回滚生效
@Transactional(rollbackFor=Exception.class)// 不对Exception回滚生效
Spring的声明式事务管理可以通过两种方式来实现:
- 基于@Transactional注解的方式。
- 基于XML的方式
2.1.1 基于@Transactional注解的方式
直接在Service层的方法上面加上@Transactional注解
在applicationContext.xml中要配置事务管理器
<!-- 事务管理器 完成手动事务管理-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--打开注解事务管理-->
<tx:annotation-driven transaction-manager="transactionManager"/>
案例实现:https://github.com/strive-xgf/SSM/commit/d855985d82db5d969a9e9820fe0686f8ce9341bc
2.1.2 基于XML的方式
- 基于XML方式的声明式事务管理是通过在配置文件中配置事务规则的相关声明来实现的。Spring框架提供了tx命名空间来配置事务。
- tx:advice元素来配置事务的通知。配置tx:advice元素时,一般需要指定id和transaction-manager属性,其中id属性是配置文件中的唯一标识,transaction-manager属性指定事务管理器。
- tx:attributes子元素,该子元素可配置多个tx:method子元素指定执行事务的细节。
- 当tx:advice元素配置了事务的增强处理后,就可以通过编写AOP配置,让Spring自动对目标对象生成代理。
需要在applicationContext.xml中配置事务和通知
案例实现:https://github.com/strive-xgf/SSM/commit/61cae51d9a69975ab2caa75249c84d484accff83
2.2 编程式事务管理
基于底层API的编程式事务管理,就是根据PlatformTransactionManager、TransactionDefinition 和 TransactionStatus 三个核心接口,通过编程的方式来进行事务处理。spring推荐使用TransactionTemplate。
在代码中显式调用 beginTransaction()、commit()、**rollback() ** 等事务处理相关的方法,这就是编程式事务管理。
TransactionTemplate的execute()方法有一个TransactionCallback接口类型的参数,该接口中定义了一个doInTransaction()方法,通常以匿名内部类的方式实现TransactionCallback 接口,并在其doInTransaction()方法中书写业务逻辑代码。这里可以使用默认的事务提交和回滚规则,在业务代码中不需要显式调用任何事务处理的API。doInTransaction()方法有一个TransactionStatus类型的参数,可以在方法的任何位置调用该参数的setRollbackOnly()方法将事务标识为回滚,以执行事务回滚。
根据默认规则,如果在执行回调方法的过程中抛出了未检查异常,或者显式调用了setRollbackOnly()方法,则回滚事务;如果事务执行完成或者抛出了checked类型的异常,则提交事务。
案例实现:https://github.com/strive-xgf/SSM/commit/fe39a52b5d2f6c692db7ed0a373c6e327cb8a267