src/main/resources
目录下新建transaction.xml
,transaction.xml
内容如下:
<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: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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="del*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Throwable" />
<tx:method name="remove*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Throwable" />
<tx:method name="clear*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Throwable" />
<tx:method name="batch*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Throwable" />
<tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Throwable" />
<tx:method name="save" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Throwable" />
<tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Throwable" />
<tx:method name="add*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Throwable" />
<tx:method name="approve*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Throwable" />
<tx:method name="submit*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Throwable" />
<tx:method name="*" propagation="SUPPORTS" read-only="true">tx:method>
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut id="pc" expression="execution(* com.xqxx.ttzcms.service..*(..))" />
<aop:advisor pointcut-ref="pc" advice-ref="txAdvice" />
aop:config>
beans>
@SpringBootApplication
修饰的类)上加上@ImportResource("classpath:transaction.xml")
注解package com.xqxx.ttzcms.config;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.transaction.interceptor.TransactionInterceptor;
/**
* 通过AOP切面设置全局事务,拦截service包下面所有方法 *
* AOP术语:通知(Advice)、连接点(Joinpoint)、切入点(Pointcut)、切面(Aspect)、目标(Target)、代理(Proxy)、织入(Weaving)
*/
@Configuration
public class TransactionManagerConfig {
// 拦截指定包下所有方法
private static final String AOP_POINTCUT_EXPRESSION = "execution (* com.xqxx.ttzcms.service..*(..))";
@Autowired
private PlatformTransactionManager transactionManager;
@Bean
public TransactionInterceptor txAdvice() {
/* 事务管理规则,声明具备事务管理的方法名 */
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
RuleBasedTransactionAttribute readOnlyRule = new RuleBasedTransactionAttribute();
readOnlyRule.setReadOnly(true);
// PROPAGATION_NOT_SUPPORTED事务传播级别5,以非事务运行,如果当前存在事务,则把当前事务挂起
readOnlyRule.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
RuleBasedTransactionAttribute requireRule = new RuleBasedTransactionAttribute();
// 抛出异常后执行切点回滚
requireRule.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
// PROPAGATION_REQUIRED:事务隔离性为1,若当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
requireRule.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 设置事务失效时间,如果超过60秒,则回滚事务
requireRule.setTimeout(60);
Map<String, TransactionAttribute> txMap = new HashMap<>();
txMap.put("add*", requireRule);
txMap.put("save*", requireRule);
txMap.put("insert*", requireRule);
txMap.put("create*", requireRule);
txMap.put("edit*", requireRule);
txMap.put("update*", requireRule);
txMap.put("modify*", requireRule);
txMap.put("delete*", requireRule);
txMap.put("remove*", requireRule);
txMap.put("drop*", requireRule);
txMap.put("clear*", requireRule);
txMap.put("submit*", requireRule);
txMap.put("approve*", requireRule);
txMap.put("reject*", requireRule);
txMap.put("forward*", requireRule);
txMap.put("get*", readOnlyRule);
txMap.put("query*", readOnlyRule);
txMap.put("find*", readOnlyRule);
txMap.put("select*", readOnlyRule);
txMap.put("list*", readOnlyRule);
txMap.put("show*", readOnlyRule);
txMap.put("view*", readOnlyRule);
txMap.put("page*", readOnlyRule);
source.setNameMap(txMap);
TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager, source);
return txAdvice;
}
@Bean
public Advisor txAdviceAdvisor() {
/*
* 声明切点的面
* 切面(Aspect):切面就是通知和切入点的结合。通知和切入点共同定义了关于切面的全部内容——它的功能、在何时和何地完成其功能。
*/
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
/* 声明和设置需要拦截的方法,用切点语言描写 */
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
/* 设置切面=切点pointcut+通知TxAdvice */
return new DefaultPointcutAdvisor(pointcut, txAdvice());
}
}
TransactionManagerConfig.java
所在的位置(包,如示例中的com.xqxx.ttzcms.config
)能否被启动类扫描,如果不能,则手动在启动类上添加@ComponentScan("com.xqxx.ttzcms.config")
注解@Transactional
注解@Transactional
注解使用在类上时,整个类的所有方法都会产生事务,使用在单个方法上时,单个方法会产生事务。
@Transactional
只能作用于类或抽象类,不能作用于接口。
@Transactional
一般放在service层的实现类上,示例:
package com.xqxx.ttzcms.service;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.xqxx.ttzcms.db.service.AbstractBookcpService;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Primary
@Service
//@Transactional
public class BookcpServiceImpl extends AbstractBookcpService {
@Transactional
public int deleteByPrimaryKey(Integer id) {
return super.deleteByPrimaryKey(id);
}
}
@Transactional
可以放在抽象类中(即service的具体实现类的父实现类),从而解决spring aop代理不了父类方法的问题。@Transactional(rollbackFor = {Throwable.class})
可以在指定类型的异常下回滚,如果是非常慎重和严谨的提交操作,一定要加上rollbackFor = {Throwable.class}
。spring aop只能代理目标类存在的方法,不能代理目标类父类的方法,从而导致有多级service实现类时,会出现事物失效。
解决办法:
super.父类方法
。@Transactional
注解。内部调用时无法触发事务,因为隐式的是this
是源对象,而不是代理对象。
怎么在内部调用而且触发事务呢?
不要使用this,而是从Spring容器里取:
applicationContext.getBean(UserService.class);
spring aop事务不生效还有其他原因,如事务的扫描包配错了、数据库不支持事务、service的方法不是public、service方法中新起了线程(线程中的代码不参与事务),这里不具体说明了。