Spring事务与定时任务线程池

        在使用Spring中@Transactional注解来修饰一个方法时,被修饰的方法内部的事务能生效的前提是该方法必须被该方法所在类之外的地方调用,所以该方法必须要声明为public。如果在方法所在类内部来调用是无法保证事务的,这与Spring的AOP的动态代理原理有关。@Transactional是基于切面来实现的,而切面的原理是动态代理,动态代理的逻辑只能从动态代理类外外部去调用才能实现。这是因为从外部调用的话,方法所在类是在动态代理类中被增强了的,被动态代理增强了的类是被Spring容器管理的。被代理类和代理增强后的类在spring容器是两个不同的bean,所以要想在被代理类内部执行代理增强后的方法,可以在被代理类中依赖注入“自己”,用依赖注入的自己来调用事务方法,这样的话依赖注入的那个“自己”是从spring容器中取出来的,是已经动态代理过后的对象了。还有另一种解决方案,可以使用(SomeClass)AopContext.currentProxy()方法拿到当前类的动态代理类之后再去调用该织入了切面的方法,同时SomeClass需要在类名上用@EnableAspectJAutoProxy(exposeProxy = true)注解修饰。

        比如某个被@Transactional修饰的方法要被定时任务来调用,且使用的是ScheduledExecutorService,即定时任务线程池来调用的话,那么定时任务线程池要定义在事务方法所在类之外,否则事务无法生效。另外事务能够生效的另一个前提是事务方法内部如果有异常,必须向方法外面抛出,即使在方法内进行了捕获,捕获处理完毕后仍然需要抛出,否则也不会触发事务回滚。那么此时就会产生一个问题,就是如果该事务方法是被一个单线程的定时任务线程池作为定时任务来执行的,方法的异常一旦向方法外抛出,会导致单线程定时任务线程池内的这个唯一的线程被terminated,从而无法执行下一个周期的定时任务,而如果在方法内自行捕获异常,虽然不会导致线程池内线程挂掉,却又无法触发事务回滚。因此处理方法可以是用定时任务触发一个方法,用该方法去调用事务方法,并用外层方法对事务方法进行try-catch,这样事务方法既能将异常抛出,保证事务回滚能够被除触发,外层线程池方法也能将异常捕获不会让线程池内线程挂掉。

  • 13
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值