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