springboot開啟聲明式事務方式
- 在Application啟動類中加入注解@EnableTransactionManagement(mode = AdviceMode.PROXY)
- 在需要加入事務的方法上加入注解@Transactional
- @Transactional(rollbackFor = RollbackException.class) 拋出指定異常時回滾
/**
* <p>
* (rollbackFor = RollbackException.class) 拋出自定義異常時,回滾事務。
* </p>
* @throws RollbackException
*/
@Override
@Transactional(rollbackFor = RollbackException.class)
public void insertThenRollback() throws RollbackException {
jdbcTemplate.execute("INSERT INTO Student (NAME) VALUES ('Tom')");
throw new RollbackException();
}
常見問題
例如有這個實現類StudentServiceImpl:
@Component
public class StudentServiceImpl implements StudentService {
/**
* <p>
* (rollbackFor = RollbackException.class) 拋出自定義異常時,回滾事務。
* </p>
* @throws RollbackException
*/
@Override
@Transactional(rollbackFor = RollbackException.class)
public void insertThenRollback() throws RollbackException {
jdbcTemplate.execute("INSERT INTO Student (NAME) VALUES ('BBB')");
throw new RollbackException();
}
/**
* <p>
* spring的事務是通過aop進行代理增強的。
* 這里是在類的內部直接執行方法調用,並沒有調用代理類來進行方法調用,所以這里事務不會回滾。
* </p>
*
* @throws RollbackException
*/
@Override
public void invokeInsertThenRollback1() throws RollbackException {
insertThenRollback();
}
}
上面的insertThenRollback()回回滾事務,invokeInsertThenRollback1()調用了insertThenRollback()方法但是不會回滾事務,這是為什么呢?
這是因為spring的事務是通過aop進行代理增強的,但這里是在類的內部直接執行方法調用,並沒有調用代理類來進行方法調用,所以這里事務不會回滾。
解決辦法
- 第一種方法:通過AopContext.currentProxy()獲取當前類的代理對象。
/**
*
* 通過AopContext.currentProxy()獲取當前類的代理對象
*
* @throws RollbackException
*/
@Override
public void invokeInsertThenRollback2() throws RollbackException {
((StudentService) (AopContext.currentProxy())).insertThenRollback();
}
- 第二種方法:把自己的實例注入進來,讓spring為我們創建代理。
//把自己的實例注入進來
@Autowired
private StudentService studentService;
/**
* 把自己的實例注入進來
* @throws RollbackException
*/
@Override
public void invokeInsertThenRollback3() throws RollbackException {
studentService.insertThenRollback();
}