1.demo地址
- github地址
2. 事务不生效
- spring 默认通过动态代理的方式实现 AOP,对目标方法进行增强,private 方法无法被代理到,spring 自然也无法动态增强事务处理逻辑
public int createUserWrong1(String name) {
try {
this.createUserPrivate(new UserEntity(name));
} catch (Exception ex) {
log.error("create user failed becauser {} ", ex.getMessage());
}
return userRepository.findByName(name).size();
}
@Transactional
private void createUserPrivate(UserEntity userEntity) {
userRepository.save(userEntity);
if (userEntity.getName().contains("test")) {
throw new RuntimeException("invalid username");
}
}
- 必须通过代理过的类从外部调用目标方法才能生效
public int createUserWrong2(String name) {
try {
this.createUserPublic(new UserEntity(name));
} catch (Exception ex) {
log.error("create user failed becauser {} ", ex.getMessage());
}
return userRepository.findByName(name).size();
}
@Transactional
public void createUserPublic(UserEntity userEntity) {
userRepository.save(userEntity);
if (userEntity.getName().contains("test")) {
throw new RuntimeException("invalid username");
}
}
- spring 通过 cglb 通过继承方式实现,private 在子类中不可见,自然无法进行事务增强, this 代表对象自己,Spring 不可能注入 this,所以通过this方法访问的必然不是代理
@Autowired
private UserService self;
public int createUserRight(String name) {
try {
self.createUserPublic(new UserEntity(name));
} catch (Exception ex) {
log.error("create user failed becauser {} ", ex.getMessage());
}
return userRepository.findByName(name).size();
}
@Transactional
public void createUserPublic(UserEntity userEntity) {
userRepository.save(userEntity);
if (userEntity.getName().contains("test")) {
throw new RuntimeException("invalid username");
}
}
3. 事务异常不回滚
- 异常必须抛出被捕获,或者手动设置回滚 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
@Transactional
public void createUserPublic1(UserEntity userEntity) {
try {
userRepository.save(userEntity);
throw new RuntimeException("error");
} catch (Exception ex) {
log.error("create user fail ", ex.getMessage());
}
- 默认捕获 RuntimeException 和 Error ,如果捕获 CheckedException 需要通过注解设置 rollbackFor=Exception.class
@Transactional
public void createUserPublic2(UserEntity userEntity) throws IOException {
userRepository.save(userEntity);
ortherTask();
}
private void ortherTask() throws IOException {
Files.readAllLines(Paths.get("file-not-exist"));
}
4. 事务传播属性配置
- 参考文章
- Spring 中的事务传播
- Spring事务管理(详解+实例)
- @Transactional 同一个类中无事务方法a()内部调用有事务方法b()的问题
- todo
5. controller调用多个service的事务方法
- 一般service方法是有事务的,把所有操作封装在一个service方法中是比较安全的。 如果在controller中调用多个service方法,只有查询的情况下是可以这样的。
6. 有问题可以留言大家一起探讨 。。。。。。