[英]Why are the transactions rolled back even when propagation=Propagation.REQUIRES_NEW in second method in Spring service class?
基本設置現在都很好,我開始嘗試交易。 Struts + Spring + Hibernate注釋事務管理器。 這是Action中的示例代碼,將調用服務類:
userService.addUser();
這是服務類中的addUser()
方法:
@Transactional(value="deu" )
public void addUser() {
userDao.addUser();
this.addUser2();
}
首先,我叫addUser
在userDAO的,這將插入一個用戶。 其次,我在此服務類的另一個方法中調用了addUser2
。
@Transactional(value="deu" , propagation=Propagation.REQUIRES_NEW )
public void addUser2() {
//should be a new transaction and will not affect the previous one.
//this one will fail but should not affect the previous one.
userDao.addUserFail();
}
由於無效PK,這一次將失敗。 我想第二次調用( addUser2
)會失敗,但不會影響前一次調用。 但是,未插入用戶。
如果我只打電話:
@Transactional(value="deu" )
public void addUser() {
userDao.addUser();
//this.addUser2();
}
它正在工作,這意味着像數據庫這樣的基本設置沒有錯。
任何的想法?
Spring的聲明式事務處理使用AOP代理。 當你得到一個tranasactional bean時,你實際上得到一個包裝你的bean實例的代理,攔截方法調用,必要時啟動一個事務,然后調用實際bean的方法,然后在必要時提交或回滾事務。
但是你從同一個bean中的另一個方法調用bean的方法,因此代理被繞過,並且不能應用任何事務行為。
將該方法放在另一個bean中,或者使用AspectJ,它可以檢測字節代碼並攔截bean內方法調用。
有關更詳細的說明,請參閱Spring文檔 。
我做了一些測試並找到了結論。
如果第二個服務(內部)是必需的並拋出異常,即使第一個事務捕獲它,它們都會回滾(因為它們在同一條船上!)
如果第二個服務(內部)是REQUIRES_NEW並拋出異常,外部必須處理這個回滾(這不是我的回滾,但我必須做一些事情),如果沒有捕獲它,外部的這個異常將觸發外部回滾(甚至這不是他的例外,但它是一個例外!)。 所以外部必須為這種情況做一些事情(設置回滾或捕獲它)。
這樣對嗎 ?
這是因為Spring AOP架構。
Spring AOP使用代理,因此只在代理上調用方法時執行方面。
調用this.addUser2(...)
您正在調用self對象上的方法,而不是代理。 因此,不執行任何方面,也不執行TX管理。
你可以做以下事情:
addUser2
方法移動到另一個bean(例如UserService2
),然后將新bean注入UserService
並使用userService2.addUser2()
調用該方法。 UserService
注入UserService
(我不確定是否可以完成),並使用userService.addUser2()
而不是this.addUser2()
調用addUser2()
this.addUser2()
。 就像Amir Pashazadeh說他不知道如何在同一個bean中使用事務上下文調用代理一樣,這是一個例子:
@Component
public class UserService(){
@Autowired @Setter private ApplicationContext applicationContext;
@Autowired @Setter private UserDao userDao;
@Transactional(value="deu" )
public void addUser() {
userDao.addUser();
try{
getProxy().addUser2();
catch(Exception ex){
// Avoid rolling back main transaction
log("OMG it failed!!")
}
}
@Transactional(value="deu" , propagation=Propagation.REQUIRES_NEW )
public void addUser2() {
//should be a new transaction and will not affect the previous one.
//this one will fail but should not affect the previous one.
userDao.addUserFail();
}
private UserService getProxy() {
return applicationContext.getBean(UserService.class);
}
}
請注意,如果你在addUser2中捕獲了異常,那么Spring似乎會拋出一個UnexpectedRollbackException ,但事務已經標記為Rollback。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.