1, 事务注解的方法要用pulbic声明, private声明会失效
理由: CGLIB通过继承方式实现代理类,private方法在子类不可见,自然也就无法进行事务增强
@Transactional
private void createUserPrivate(UserEntity entity) {}
2, 不能调用同类里的事物方法. 必须通过调用事物增强的代理类 的目标方法才能生效。
事务是基于动态代理实现的, 调用类里面的方法 self.createUserPublic() (调用的是UserService.createUserPublic()) 就得不到增强了, 必须要调用代理类的方法才会增强(使用到事物)
**代理类增强: 开启事物
目标方法
提交事物/ 回滚事物**
public UserService{
public int createUserWrong2(String name) {
try {
this.createUserPublic(new UserEntity(name));
} catch (Exception ex) {
log.error("create user failed because {}", ex.getMessage());
}
return userRepository.findByName(name).size();
}
}
/
/标记了@Transactional的public方法
@Transactional
public void createUserPublic(UserEntity entity) {
userRepository.save(entity);
if (entity.getName().contains("test"))
throw new RuntimeException("invalid username!");
}
3, try…catch 处理过的异常 不会回滚
//异常无法传播出方法,导致事务无法回滚
@Transactional
public void createUserWrong1(String name) {
try {
userRepository.save(new UserEntity(name));
throw new RuntimeException("error");
} catch (Exception ex) {
log.error("create user failed", ex);
}
}
4, 受检异常回滚 @Transactional(rollbackFor = Exception.class),默认不回滚受检异常
有这么一个场景:一个用户注册的操作,会插入一个主用户到用户表,还会注册一个关联的子用户。我们希望将子用户注册的数据库操作作为一个独立事务来处理,即使失败也不会影响主流程,即不影响主用户的注册。
1, 子用户创建使用开启新事物(propagation = Propagation.REQUIRES_NEW)
2, 在创建用户方法中 子用户创建用try…catch处理异常
@Autowired
private UserRepository userRepository;
@Autowired
private SubUserService subUserService;
@Transactional
public void createUserWrong(UserEntity entity) {
createMainUser(entity);
try{
// 子用户创建, try..catch后出现异常, 主用户创建不会回滚
subUserService.createSubUserWithExceptionWrong(entity);
}catch (Exception ex) {
}
}
private void createMainUser(UserEntity entity) {
userRepository.save(entity);
log.info("createMainUser finish");
}
@Service
@Slf4j
public class SubUserService {
@Autowired
private UserRepository userRepository;
// (propagation = Propagation.REQUIRES_NEW)必须要开启新的事务, 不然与主用户创建在同一事务中, 会一起回滚
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void createSubUserWithExceptionWrong(UserEntity entity) {
log.info("createSubUserWithExceptionWrong start");
userRepository.save(entity);
throw new RuntimeException("invalid status");
}
}