Spring事务控制说明
- Java EE体系进行分层开发,事务处理处于业务层,Spring提供了分层设计业务层的事务解决方案
- Spring框架为我们提供了一组事务的控制接口,具体在下面介绍
- Spring的事务控制都是基于AOP的,他可以通过编程方式实现,也可以通过配置方式实现(声明式),现在常用配置的方式实现事务的管理
Spring事务控制的API
- PlatformTransactionManager接口(了解)
- 获取事务状态信息:
TranscationStatus getTransaction(TransactionDefinition definition) - 提交事务:
void commit(TranscationStatus status) - 回滚事务:
void rollback(TranscationStatus status)
- 获取事务状态信息:
- TransactionDefinition的方法(了解)
- 获取事务对象名称:String getName()
- 获取事务隔离级别:int getIsolationLevel()
- 获取事务传播行为:int getPropagtionBehavior()
- 获取事务超时时间:int getTimeout()
- 获取事务是否只读:boolean isReadOnly()
- TransactionStatus的方法(了解)
- 刷新事务:void flush()
- 获取是否存在存储点:boolean hasSavepoint()
- 获取事务是否完成:boolean isCompleted()
- 获取事务是否为新事务:boolean isNewTransaction()
- 获取事务是否回滚:boolean isRollbackOnly()
- 设置事务回滚:void setRollbackOnly()
- 我们在开发中使用PlatformTransactionManager接口的实现类
- 使用 Spring JDBC 或 iBatis 进行持久化数据时
org.springframework.jdbc.datasource.DataSourceTransactionManager - 使用 Hibernate 版本进行持久化数据时
org.springframework.orm.hibernate5.HibernateTransactionManager
- 使用 Spring JDBC 或 iBatis 进行持久化数据时
- 事务隔离级别(反映事务提交并发访问时的处理态度)
- ISOLATION_DEFAULT:默认级别,表示使用数据库的默认隔离级别,归属下列某一种
- ISOLATION_READ_UNCOMMITTED:可以读取未提交的的数据
- ISOLATION_READ_COMMITTED:只能读取已提交数据,解决脏读问题(Oracle默认级别)
- ISOLATION_REPEATABLE_READ:是否读取其他事务提交修改后的数据,解决不可重复读的问题(Mysql默认级别)
- ISOLATION_SERIALIZABLE:是否读取其他事务提交添加后的数据,解决幻读问题
- 事务的传播行为:
- REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,就如到事务中(默认值,一般选择)
- SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
- MANDATORY:使用当前事务,如果没有事务就抛出异常
- REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起
- NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
- NEVER:以非事务方式运行,如果当前存在事务,抛出异常
- NESTED::如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作
基于XML的声明式事务控制(只需配置XML,其他层的代码不用改,到层用了JdbcTemplate)
- 第一步:配置事务管理器(class里面的内容是固定的)
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
- 第二步:配置事务的通知引用事务管理器
<!-- 事务的配置 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager"> </tx:advice>
第三步:配置事务的属性
<!--在 tx:advice 标签内部 配置事务的属性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--
配置事务的属性:
name:指定需要配置事务属性的方法,可以是完整的方法名,可以为*表示全部方法,也可以为find*表示以find开头的方法,同事存在多个<tx:method>时,name的范围越小,优先级越高
isolation:用于指定事务的隔离级别,默认值是DEFAULT,表示使用数据库的默认隔离级别
propagation:用于指定事务的传播行为,默认值是REQUIRED,表示一定会有事务,增删改的选择REQUIRED,查询选择SUPPORTS
read-only:用于指定事务是否只读,只有查询才能设置成true,表示只读,默认值为false,表示读写
timeout:用于指定事务的超时时间,默认值为-1,表示永不超时,如果要指定数值,单位为秒
rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚,没有默认值。表示任何异常都回滚
no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚,没有默认值。表示任何异常都回滚
-->
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" read-only="false"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method>
</tx:attributes>
</tx:advice>
- 第四步:配置 AOP 切入点表达式
<!--配置AOP-->
<aop:config>
<!--配置切入点表达式-->
<aop:pointcut id="p" expression="execution(* com.zsc.service.impl.*.*(..))"/>
</aop:config>
- 第五步:配置切入点表达式和事务通知的对应关系
<!-- 在 aop:config标签内部:建立事务的通知和切入点表达式的关系 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="p"/>
- 我的理解:
AOP先拦截匹配的方法,然后传给事务管理器,事务管理器也做了一次方法的拦截,使范围越来越小,最后拦截方法配置事务的属性
基于注解的配置方式
- 需要基于XML配置的第一步配置事务管理器
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
- 中开启 spring 对注解事务的支持
<!--开启注解事务的支持-->
<tx:annotation-driven transaction-manager="transactionManager"/>
- 在业务层中使用@Transactional 注解
// 可以使用在类似表示该类的所有方法都有效,也可以使用在方法上表示只读该方法有效,作用在方法上的比作用在类上的优先级高
@Transactional(readOnly=true,propagation=Propagation.SUPPORTS)
- 开启事务也可以在配置类中使用@EnableTransactionManagement 注解