因为线程不属于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......
}
}