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"); } }