注解式事务问题
spring注解事务控制的最小粒度是方法,也就是说如果你有某些非同一事务或非事务的长时间流程就应该另起一个方法
- 例如下面,如果userService.saveUser()的传播属性是new而且执行时间很长要5s,那么执行到第二个事务userService.saveUser()时,第一个事务save()会被挂起,挂起的事务会占用线程池连接,浪费5s的资源
- 例如下面,redisTemplate.opsForValue().set(“key1”,“value1”)需要5s,业务上如果可以接受该方法失败抛异常,那么在此之前就应该提交事务,redisTemplate就不应该包裹在同一个事务方法中
- 第三方调用和异步线程也是同样的问题,业务上如果可以接受该方法失败抛异常就不该和事务写在同一方法里
@Transactional
public void save(){
userService.saveUser();
cityservice.saveCity();
redisTemplate.opsForValue().set("key1","value1");
new Thread(() -> System.out.println("记录日志,业务允许无视该业务异常")).start();
}
编程式事务使用方法
- 配置transactionTemplate
@Bean
public TransactionTemplate transactionTemplate(PlatformTransactionManager platformTransactionManager) {
TransactionTemplate transactionTemplate = new TransactionTemplate();
transactionTemplate.setTransactionManager(platformTransactionManager);
return transactionTemplate;
}
- 每个transactionTemplate.execute()都是一个独立的事务,执行完会自动提交
@Service
public class testService {
@Autowired
private UserService userService;
@Autowired
private Cityservice cityservice;
@Autowired
private TransactionTemplate transactionTemplate;
public void t(){
//第一个事务
Integer execute = transactionTemplate.execute(status -> userService.saveUser());
//第二个事务
Integer execute2 = transactionTemplate.execute(status -> cityservice.saveCity());
}
}
- 自己通过try-catch控制事务
@Autowired
private PlatformTransactionManager platformTransactionManager;
public void t2(){
DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();//事务配置
defaultTransactionDefinition.setPropagationBehavior(0);
TransactionStatus transaction = platformTransactionManager.getTransaction(defaultTransactionDefinition);//开启事务
try {
System.out.println("业务代码");
}catch (Exception e){
platformTransactionManager.rollback(transaction);//回滚
}
platformTransactionManager.commit(transaction);//提交
}