多線程事務處理問題


代碼

EquipCollectServiceImpl.java
protected static final ExecutorService handleTaskPoolExecutor = Executors.newFixedThreadPool(3);
public void queryDataToUpload(){
	// 查詢待上傳信息
	List list = equipCollectDao.queryDataByParams();
	// 多線程 調用上傳接口
	handleTaskPoolExecutor.submit(
		@Override
		new Runnable(){
			public void run(){
				// ... 接口調用 ...
				Json backInfo = {..};
				// 保存接口日志(方式 1) -> 報錯
				interfaceDao.insertInterfaceBackLog(backInfo);
				// 保存接口日志(方式 2) -> 2.1報錯 2.2成功
				saveInterfaceBackLog(backInfo);
				// 保存接口日志(方式 3) -> 成功
				interfaceService.insertInterfaceBackLog(backInfo);
			}
		}
	);
}
@Transactional
public void saveInterfaceBackLog(Json backInfo){
	// 方式 2.1
	interfaceDao.insertInterfaceBackLog(backInfo);
	// 方式 2.2
	interfaceService.insertInterfaceBackLog(backInfo);
}

報錯說明
insertInterfaceBackLog()方法中使用 查詢 報:

java.util.concurrent.ExecutionException: org.hibernate.HibernateException: 
Could not obtain transaction-synchronized Session for current thread

insertInterfaceBackLog()方法中使用 保存 報:

org.springframework.dao.InvalidDataAccessApiUsageException: 
Write operations are not allowed in read-only mode (FlushMode.MANUAL): 
Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.

問題分析
查詢 this.getSessionFactory().getCurrentSession() 獲取不到session,然后直接報錯;
保存 this.getSessionFactory().getCurrentSession() 獲取不到session,會創建新session,但是FlushMode.MANUAL < FlushMode.COMMIT,然后報錯;
spring-orm-4.3.4.RELEASE.jar源碼如下:

if (session == null) {
	session = this.getSessionFactory().openSession();
	session.setFlushMode(FlushMode.MANUAL);
	isNew = true;
}

總結
多線程內部不被事務控制,獲取不到session,但是能夠獲取spring注入的bean;
多線程內部執行同類中方法,不會分配新事務(注解,AOP切面 均不生效);
方式 3,方式 2.2 每執行一次就會啟動一個事務;不會影響到同線程的其他事務;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM