JavaEE体系进行分层开发,事务处理位于业务层。
spring提供了分层设计业务层的事务处理方案,spring的事务控制是基于aop的。
一、PlatformTransactionManager
此接口是spring的事务管理器,提供了常用的操作事务的方法
管理事务的子类对象:
(1)DataSourceTransactionManager:使用SpringJDBC或IBatis进行持久化数据时使用
(2)HibernateTransactionManager:使用Hibernate版本进行持久化数据时使用
二、基于XML的声明式事务控制
配置步骤
第一步:配置事务管理器
第二步:配置事务的通知引用事务管理器
第三步:配置事务的属性
第四步:配置AOP切入点表达式
第五步:配置切入点表达式和事务通知的对应关系
<tx:method name=""/>
name属性:用于匹配需要织入事务的方法,设置匹配规则
isolation:事务的隔离级别,默认值是DEFAULT,数据库级别的
propagation:表示是否开启事务,以什么样的策略开启:REQUIRED表示一定会开启事务,无论是增删改查都会开启
SUPPORTS表示有事务就会开启事务,没有事务就不会开启,会在增删改的场景下开启事务,查询场景不会开启
即对数据有影响就开启事务
read-only:是否只读:true是 false否 ,默认值是true,在查询的业务场景下,会把该属性设置成true
timeout:表示超时时间,默认值是-1,永不超时,如果是正数的话,可以以秒为单位,设置超时时间
rollback-for:是否开启回滚:true 除了传的这个异常回滚之外,所有异常都不回滚
no-rollback-for 除了传的这个异常不回滚之外,所有异常回滚
默认情况下所有的异常都回滚
只有在增删该的业务场景下,才会去开启事务,查询业务场景下不用开启事务或者是只读就行
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="service" class="com.jy.tx.account.service.AccountServiceImpl"></bean>
<bean id="dao" class="com.jy.tx.account.dao.AccountDaoImpl"></bean>
<!--注册jdbcTemplate实例-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--注册数据源实例-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!--注入源数据-->
<property name="url" value="jdbc:mysql://localhost:3306/test?serverTimezone=GMT&characterEncoding=utf-8"></property>
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--配置事务管理器-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源实例-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置事务通知,引用事务管理器-->
<tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">
<!--配置事务的属性-->
<tx:attributes>
<tx:method name="update*" propagation="REQUIRED" read-only="false"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<!--配置aop-->
<aop:config>
<!--配置一个切入点表达式-->
<aop:pointcut id="pt01" expression="execution(* com.jy.tx.account.service.*.*(..))"/>
<!--配置切入点和事务通知的对应关系-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt01"></aop:advisor>
</aop:config>
</beans>
三、基于注解的声明式事务控制@Transactional
事务注解,可以修饰类,也可以修饰方法,修饰类时,该类下所有的方法都会加入事务的支持,修饰方法时只有指定方法会加入事务支持,方法的优先级比类高。
使用注解时事务管理器仍需要配置,但可以免去事务通知的配置。
在同一个类中,非事务方法调用事务方法,事务不会开启,或者说无事务注解的方法调用有事务注解的方法时,注解不会生效。**@Transactional**
的原理是什么?
首先@Transactional是基于spring aop的,对于spring中aop实现原理有了解的话,应该知道想要对一个方法进行代理的话,肯定需要定义切点。在@Transactional的实现中,同样如此,spring为我们定义了以 @Transactional 注解为植入点的切点,这样才能知道@Transactional注解标注的方法需要被代理。
有了切面定义之后,在spring的bean的初始化过程中,就需要对实例化的bean进行代理,并且生成代理对象。
生成代理对象的代理逻辑中,进行方法调用时,需要先获取切面逻辑,@Transactional注解的切面逻辑类似于@Around,在spring中是实现一种类似代理逻辑。