最近有个需求-当删除旧数据然后保存新数据时,只有删除旧数据成功同时保存新数据成功才可以不然的话就回滚,因为新数据保存那数据量比较大由子线程完成,然后删除数据是在主线程完成。
在方法上加上如下注解,看似可以其实不行,因为主线程与子线程不是同一个事务
@Transactional(rollbackFor = Exception.class)
@Transactional失效有如下场景
1.@Transactional修饰的方法为非public方法
因为@Transactional是基于动态代理来实现的,非public的方法,@Transactional的动态代理对象信息为空,所以不能回滚。
2.在类内部没有添加@Transactional的方法,调用@Transactional方法时
@Transactional是基于动态代理对象来实现的,而在类内部的方法的调用是通过this关键字来实现的,没有经过动态代理对象,所以事务回滚失效。
3.在@Transactional方法内部捕获了异常,没有在catch代码块里面重新抛出异常,事务也不会回滚
4.方法用final或static修饰
如果某个方法用final修饰了,那么在它的代理类中,就无法重写该方法而添加事务功能。
5.未被spring管理
通常情况下,我们通过@Controller、@Service、@Component、@Repository等注解,可以自动实现bean实例化和依赖注入的功能。
6.未开启事务
7.多线程调用
同一个事务,其实是指同一个数据库连接,只有拥有同一个数据库连接才能同时提交和回滚。
8.表不支持事务
可以看看数据库引擎
创建事务管理器
@Componentpublic class txManagerConfig {// 创建事务管理器@Bean(name = "txManager")public PlatformTransactionManager txManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}}
实现代码
@Autowiredprivate PlatformTransactionManager txManager;private boolean isExec = false;@Override@Transactional(rollbackFor = Exception.class)public R save(List<XXXDataDTO> params) {if (params == null || params.isEmpty()) {return R.error("没有数据,保存失败!");}try {//判断有无该条记录的旧数据,有则删除......//开启线程,执行新数据保存Callable<Object> callable = new Callable<Object>() {@Overridepublic Object call() throws Exception {DefaultTransactionDefinition def = new DefaultTransactionDefinition();def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);TransactionStatus status = txManager.getTransaction(def);try {//新数据保存......// 提交事务mit(status);} catch (Exception e) {// 回滚事务txManager.rollback(status);throw new RuntimeException();}return "success";}};FutureTask<Object> futureTask = new FutureTask<Object>(callable);thread = new Thread(futureTask);thread.start();System.out.println(futureTask.get());} catch (Exception e) {e.printStackTrace();isExec = true;throw new RuntimeException("xxx保存失败!");} finally {if (thread.isAlive()) {thread.interrupt();}}return isExec ? R.error("保存失败!") : R.ok();}