Foreword
Recently when refactoring code and found a serious bug: error after the transaction method, does not even roll back, because I have to catch the exception, the following specific reasons speak. Fear very fine thinking, the whole project is the kind of writing. So, to begin research and testing @Transactional comment.
@Transactional can help us to automatically manage transactions. Usually in the process of service plus the annotation layer. But there are a lot of pit! The following codes are shapeless code, commonly known as pseudo-code.
A pit: valid only for external calls
Internal call transaction method causes the transaction invalid because of spring dynamic proxies for transaction management, external calls can only intercept, unable to manage internal calls.
class UserController {
// 外部调用,受事务管理
userService.saveUser();
}
class UserService {
@Transation
public void saveUser() {}
public void saveUserInternal() {
// 内部调用,不受事务管理
saveUser();
}
}
The solution: get a proxy object, and the object through a proxy to call
the first step, open exposure to Agent
<aop:aspectj-autoproxy expose-proxy="true" />
The second step, through a proxy object to call the transaction method
((UserService)AopContext.getProxy()).saveUser();
Pit II: valid only for public methods
Because the transaction annotation only effective external call (refer to pit a), private method can only be called internally, so private invalid well understood. But why protected invalid. stackoverflow of this answer to explain my confusion.
This means that: JDK agent does not support interception of protected methods, but CGLIB is possible, but not recommended, then Spring in order to unify those guys, cut directly support protected method.
Hang three: Unchecked exceptions only effective
What is abnormal subjects and Unchecked exceptions? Simply put, the subject is abnormal or if you do not catch the exception thrown, then the compiler will complain, common, such as FileInputStream, you either catch the exception, or throw an exception.
Solution: @Transactional (rollbackFor = Exception.class)
@Transactional(rollbackFor = Exception.class)
public void saveFile() throws FileNotFoundException {
// 数据操作
userDao.saveUser();
// 会抛出异常,因为设置了rollbackFor属性,会回滚
InputStream in = new FileInputStream(new File("xxx.xxx");
}
Hang four: only valid for an exception thrown
Exception caught, the equivalent of hidden anomalies, abnormal does not automatically rollback. If you must capture, capture manually rolled back inside the code block
@Transactional
public void saveUser() {
try {
saveUser();
} catch(Exception e) {
// 手动关闭事务
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
Outstanding
I encounter when debugging a problem, the transaction method, the first after deleting the query is normal; but after saving the first check, you can not find the saved data. You big brother, if you know what the reason may demand lower.