事务有两种配置方式
1. 使用@Transactional显式的注解式事务
2. 声明式事务,又叫隐式事务,所以不是没有加@Transactional注解就一定没有事务
下面是一个声明式事务的使用场景,其使用了spring Transaction底层的api支持,如PlatformTransactionManager
Spring 的事务机制提供了一个 PlatformTransactionManager 接口,不同的数据访问技术的事务使用不同的接口实现。
使用JPA作为数据库访问技术时,spring boot使用的是 JpaTransactionManager,而使用JDBC作为数据库访问技术时,spring boot使用的是 DataSourceTransactionManage
实际工作中,spring的建议是你在具体的类(或类的方法上)使用@Transactional注解,service下每个类的每个方法都让我们加上@Transactional注解,工作量有点大,也有时候会忘,所以经常看到有开发团队配置拦截式事务
只需要在我们的项目中新增一个子类AspectjTransactionConfig即可
@Configuration
@EnableTransactionManagement
public class AspectjTransactionConfig {
public static final String transactionExecution = "execution(* com.hfi.service..*.*(..))";
@Autowired
private PlatformTransactionManager transactionManager;
/**
* 定义通知类
* @return
*/
@Bean
public DefaultPointcutAdvisor defaultPointcutAdvisor() {
// 指定不同的方法用不同的策略 查询基本上不需要事务支持
Properties attributes = new Properties();
// attributes.setProperty("get*", "PROPAGATION_REQUIRED,-Exception");
attributes.setProperty("add*", "PROPAGATION_REQUIRED,-Exception");
attributes.setProperty("save*", "PROPAGATION_REQUIRED,-Exception");
attributes.setProperty("update*", "PROPAGATION_REQUIRED,-Exception");
// attributes.setProperty("select*", "PROPAGATION_REQUIRED,-Exception");
// 创建interceptor
TransactionInterceptor interceptor = new TransactionInterceptor(transactionManager, attributes);
// 定义切入点:指定一般要拦截哪些类
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(transactionExecution);
// 配置通知类advisor
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
advisor.setPointcut(pointcut);
advisor.setAdvice(interceptor);
return advisor;
}
}
这样我们的service就自动拥有了事务,可以加@Transactional类覆盖全局的配置
测试:
public Employee saveTwoEmployee(Employee employee) {
// 模拟两次执行
addEmp(employee);
// int template = 5/0;
employee.setLastName("cl");
Employee employee1 = addEmp(employee);
return employee1;
}
当我们启用了DefaultPointcutAdvisor,事务在执行完第一个addEmp之后,报错后,会回滚。而没有启用DefaultPointcutAdvisor,事务不会回滚。