1. 程式人生 > >spring多執行緒中事務處理

spring多執行緒中事務處理

什麼是事務:參考連結:https://blog.csdn.net/sinat_33536912/article/details/51200630

專案中遇到的問題:

在加有事務的類中啟用執行緒,執行緒不會重新開啟新的事務而是與當前類共用事務。事務的提交也是一起進行。

程式碼:

import com.transaction.dao.UserDao;
import com.transaction.handler.ThreadHandler;
import com.transaction.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
@Service
@Transactional
public class TestService {
    @Autowired
    private UserDao userDao;
    @Autowired
    private ThreadHandler threadHandler;
    public void testTransaction (){
        try{
            User user=new User();
            user.setUserphone("18255556666");
            user.setUsername("孔空空");
            user.setCreateDate(new Date());
            userDao.insert(user);
            threadHandler.testHandler();
            System.out.println("執行緒執行完畢");
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("testService 異常");
        }
    }
    //查詢使用者方法,多執行緒下呼叫
    public void selectUser (){
        System.out.println("查詢開始");
        User user=userDao.selectUser("孔空空");
        System.out.println(user.getId());
    }
}

//多執行緒下查詢使用者資料
@Service("threadHandler")
public class ThreadHandler {
    public static Log logger = LogFactory.getLog(ThreadHandler.class);
    @Autowired
    private Executor taskAsyncPool;
    @Autowired
    private TestService testService;
    public void testHandler() {
        taskAsyncPool.execute(new Runnable() {
            @Override
            public void run() {
                logger.info("測試多執行緒事務任務啟動");
                try {
                    testService.selectUser();
                    Thread.sleep(1200000);
                    System.out.println("testHandler執行緒執行完畢");
                }catch(Exception e) {
                    e.printStackTrace();
                    logger.info("系統異常===="+e);
                }
            }
        });
    }
}

執行結果:丟擲空指標異常。。。。。。。

原因:

testTransaction方法中呼叫執行緒去查詢user表中的資料,線上程中讓執行緒等待,保證testTransaction中的插入執行完畢,但是執行緒中呼叫查詢方法時發現user表中並沒有剛剛插入的資料,也就是testTransaction的事務沒有提交,因為執行緒還沒有執行完畢。通過這個實驗發現,新開啟的執行緒並沒有開啟新的事務,而是跟service中的方法公用同一個事務,這才導致查詢方法中出現空指標異常的情況。

解決方法:在多執行緒的方法上加註解

@Transactional(propagation = Propagation.REQUIRES_NEW)

@Transactional(propagation = Propagation.REQUIRES_NEW)在多執行緒的方法或類上加上該註解,那麼執行緒就會新開啟一個事務,與service中的事務沒有關係。service中方法執行完畢之後就提交它的事務,多執行緒的事務自己管理。

程式碼:

@Service("threadHandler")
public class ThreadHandler {
    public static Log logger = LogFactory.getLog(ThreadHandler.class);
    @Autowired
    private Executor taskAsyncPool;
    @Autowired
    private TestService testService;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void testHandler() {
        taskAsyncPool.execute(new Runnable() {
            @Override
            public void run() {
                logger.info("測試多執行緒事務任務啟動");
                try {
                    testService.selectUser();
                    Thread.sleep(1200000);
                    System.out.println("testHandler執行緒執行完畢");
                }catch(Exception e) {
                    e.printStackTrace();
                    logger.info("系統異常===="+e);
                }
            }
        });
    }
}

加註解之後的結果:查詢正常並沒有出現空指標的情況

 

注意:在用該註解時,還發現了個問題,在同一類中使用Propagation.REQUIRES_NEW註解,該註解不作用,只有在不同的類中使用該註解才會重新開啟新的事務。至於為什麼還沒有進行深究。。。。。