`
solomon523
  • 浏览: 14857 次
社区版块
存档分类
最新评论

spring 多线程事务的问题

阅读更多

因为线程不属于spring托管,故线程不能够默认使用spring的事务,也不能获取spring注入的bean

在被spring声明式事务管理的方法内开启多线程,多线程内的方法不被事务控制。

 

如下代码,线程内调用insert方法,spring不会把insert方法加入事务

就算在insert方法上加入@Transactional注解,也不起作用。

(?不解,试过将serviceA变成多例,也不行)

@Service
public class ServiceA {
 
    @Transactional
    public void threadMethod(){
        this.insert();
         System.out.println("main insert is over");
        for(int a=0 ;a<3;a++){
            ThreadOperation threadOperation= new ThreadOperation();
            Thread innerThread = new Thread(threadOperation);
            innerThread.start();
        }
    }
 
    public  class ThreadOperation implements Runnable {
        public ThreadOperation(){
        }
        @Override
        public void run(){
            insert();
            System.out.println("thread insert is over");
        }
    }
 
    public void insert(){
 
    //do insert......
 
    }
}

 

 

如果吧上面insert方法提出到新的类中,加入事务注解,就能成功的把insert方法加入到事务管理当中

@Service
public class ServiceA {
 
@Autowired
private ServiceB serviceB;
 
    @Transactional
    public void threadMethod(){
        this.insert();
        System.out.println("main insert is over");
        for(int a=0 ;a<3;a++){
            ThreadOperation threadOperation= new ThreadOperation();
            Thread innerThread = new Thread(threadOperation);
            innerThread.start();
        }
    }
 
    public  class ThreadOperation implements Runnable {
        public ThreadOperation(){
        }
        @Override
        public void run(){
            serviceB.insert();
            System.out.println("thread insert is over");
        }
    }
 
    public void insert(){
 
        //do insert......
 
    }
}
 
@Service
public class ServiceB {
 
    @Transactional
    public void insert(){
 
        //do insert......
 
    }
 
}

 

 

 

另外,使用多线程事务的情况下,进行回滚,比较麻烦。

thread的run方法,有个特别之处,它不会抛出异常,但异常会导致线程终止运行。

最麻烦的是,在线程中抛出的异常即使在主线程中使用try...catch也无法截获

这非常糟糕,我们必须要“感知”到异常的发生。比如某个线程在处理重要的事务,当thread异常终止,我必须要收到异常的报告,才能回滚事务。

这时可以使用线程的UncaughtExceptionHandler进行异常处理,UncaughtExceptionHandler名字意味着处理未捕获的异常。更明确的说,它处理未捕获的运行时异常

 

如下代码

线程出要使用

①处要抛出异常

②处要捕捉异常,并且要抛出RuntimeException

③处手动处理回滚逻辑

@Service
public class ServiceA {
 
@Autowired
private ServiceB serviceB;
 
    @Transactional
    public void threadMethod(){
        this.insert();
        System.out.println("main insert is over");
        for(int a=0 ;a<3;a++){
            ThreadOperation threadOperation= new ThreadOperation();
            Thread innerThread = new Thread(threadOperation);
            innerThread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
               public void uncaughtException(Thread t, Throwable e) {
                   try {
                        serviceB.delete();③
                   } catch (Exception e1) {
                       e1.printStackTrace();
                   }
               }
            });
            innerThread.start();
        }
    }
 
    public  class ThreadOperation implements Runnable {
        public ThreadOperation(){
        }
        @Override
        public void run(){
            try {
               serviceB.insert();
           }catch (Exception ex){ ②
            System.out.println(" Exception in run ");
               throw new RuntimeException();
           }
            System.out.println("thread insert is over");
        }
    }
 
    public void insert(){
 
        //do insert......
 
    }
}
 
@Service
public class ServiceB {
 
    @Transactional
    public void insert() throws Exception{ ①
 
    //do insert......
 
    }
 
    @Transactional
    public void delete() throws Exception{ 
 
        //do delete......
 
    }
 
}

 

 

分享到:
评论
1 楼 Mind-Hacks 2016-11-02  
哥们我按照你的说法,终于成功了。我是在本类启动的多线程,然后调用本类的方法,也是没有事务,把run()方法里面的service移动出去就好了。
不过我找到原因了,哈哈哈,因为调用本类的方法,会让注解,还是AOP切面无法注切入(具体看事务管理实现源码)。调用别的类的话,然后就会有事务切入,然后就会有管理     

相关推荐

Global site tag (gtag.js) - Google Analytics