1.目标
从事务角度:一个事务方法中包含多个数据库操作,要么一起提交,要么一起回滚。也就是说事务方法中的多个数据库操作,有任何一个失败,整个事务全部回滚
从声明式角度:由spring来全面接管数据库事务。用声明式代替编程式
2.流程
3.操作
3.1加入AOP依赖包
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
</dependency>
3.2创建配置文件
spring-persist-tx.xml
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
</beans>
3.3配置事务管理器
<!--配置自动扫描的包:主要是把业务逻辑层Service扫描到IOC容器中-->
<context:component-scan base-package="com.pl.service"/>
<!--配置事务管理器-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--装配数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
3.4配置AOP
<!--配置事务切面-->
<aop:config>
<!--避免把UserDatailsService加入事务控制,让切入点表达式定位到ServiceImpl-->
<aop:pointcut id="txPointcut" expression="execution(* *..*ServiceImpl.*(..))"/>
<!--将切入表达式和事务通知关联起来-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
3.5配置事务属性
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!--配置事务属性-->
<tx:attributes>
<!--查询方法:配置只读属性,让数据库知道这是一个查询操作,能够进行一定的优化-->
<tx:method name="get*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="query*" read-only="true"/>
<tx:method name="count*" read-only="true"/>
<!--增删改方法:配置事务的传播行为,回滚异常-->
<!--
propagation属性:
REQUIRED:默认值,表示当前方法必须工作在事务中,如果当前线程没有已经开启的事务,则自己开启新的事务。如果已经有了,那么就使用已有的事务
顾虑:用别人的事务可能被回滚
REQUIRES_NEW:建议使用的值,表示不管当前线程上有没有事务都要自己开事务,在自己的事务中运行
好处:不会受其他事务回滚的影响
-->
<!--
rollback-for属性: 配置事务方法针对什么样的异常回滚
默认:根据运行时异常回滚
建议:编译时和运行时异常都回滚
-->
<tx:method name="save*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception"/>
<tx:method name="update*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception"/>
<tx:method name="remove*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception"/>
<tx:method name="batch*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception"/>
</tx:attributes>
</tx:advice>