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