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. 有問題可以留言大家一起探討 。。。。。。