1. 程式人生 > >spring中事務傳播下,特殊方法手動控制事務

spring中事務傳播下,特殊方法手動控制事務

在開發中,遇到事務問題:從excel檔案中解析匯入資料,每個sheet頁中的資料作為單個的事務單元提交資料庫。解析下程式碼實現:

方法①:mainAnalysisEntrance(…)解析excel入口和許可權和其他業務等處理;
方法②:analysisWorkbook(…)解析excel工作簿;
方法③:analysisPerSheet(…)解析每一個sheet頁資料,並將其中通過的資料,作為一個事務單元,提交資料庫;
方法④:analysisPerRow(…)解析excel中sheet中的每一行;
方法⑤:notSupportBatchAllDBByPerSheetDatas(…)此方法持久化sheet頁資料.此方法手動單方法處理事務.


遇到問題:方法⑤每次都不會單獨作為事務單元提交sheet頁資料,等到方法③執行全部完成,才會提交所有sheet頁資料,或全部回滾所有sheet頁資料,違背一開始的當sheet頁作為事務的提交方案。

簡略程式碼附入:

……
import jxl.*;
……
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.support.DefaultTransactionDefinition;
……
@Service("smartImportService")
public class SmartImportServiceImpl implements SmartImportService {

	//log
	private static final Logger LOG = LoggerFactory.getLogger(LawCaseAllSmartImportSchemeServiceImpl.class);
	
	@Autowired
	private AMapper aMapper;
	@Autowired
	private ApplicationContext ctx;
	
	public JsonResult mainAnalysisEntrance(InputStream is, Object ... args) {
		……
		Workbook book = Workbook.getWorkbook(is);
		……
		return analysisWorkbook(book, args);
		……
	}
	
	public JsonResult analysisWorkbook(Workbook book, Object ... args) throws Exception{
	……
	for(int sheetIndex = 0; sheetIndex < allSheetCount; sheetIndex++){
		……
		break;
		……
		BusinessResult businessSheetResult = analysisPerSheet(sheet, args0);
		……
	}
	……//finally中關閉
	book.close();
	……
	return jsonResult;
	}

	public BusinessResult analysisPerSheet(Sheet sheet, Object ... args) throws Exception{
		……
		for(int rowIndex = 2; rowIndex < rows; rowIndex++){
			……
			Map<String, Object> rowRes = analysisPerRow(cells, args);
			……
		}
		……
		Object [] objLists = new Object[6];
		//把當前sheet頁中ok的資料持久化資料
		boolean db_res = notSupportBatchAllDBByPerSheetDatas(objLists);
	}

	public Map<String, Object> analysisPerRow(Cell [] cells, Object ... args) throws Exception{
		//行資料驗證和解析
	}

	public boolean notSupportBatchAllDBByPerSheetDatas(Object ... lists){
		DataSourceTransactionManager txManager = (DataSourceTransactionManager) ctx.getBean("transactionManager");
		DefaultTransactionDefinition def = new DefaultTransactionDefinition();
		def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);// 事物隔離級別,開啟新事務
		TransactionStatus txStatus = txManager.getTransaction(def);// 獲得事務狀態
		try {
			List<AEntity> aList = (List<AEntity>) lists[0];
			……
			if(aList != null && !aList.isEmpty()){
					int aRows = aMapper.batchInsertA(aList);
					if(aRows != aList.size()){
						SmartImportSchemeAssist.printTrackingMsg(LOG, "批量插入每個sheet頁中所有涉及到資料庫的資料:A表,資料插入不一致,回滾事務.");
	//					TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();  //--此回滾為手動但失效,並且不推薦
	//					return false;
						throw new RuntimeException();
					}
			}
			……
			txManager.commit(txStatus);//事務處理成功,提交當前事務
			return true;
		} catch (Exception e) {
			SmartImportSchemeAssist.printErrMsg(LOG, "批量插入每個sheet頁中所有涉及到資料庫的資料操作異常,回滾事務.", e);
			txManager.rollback(txStatus);//事務處理失敗,回滾當前事務
		}
		return false;
	}
}


@Service("allSmartImportSchemeAssist")
public class SmartImportSchemeAssist {
	/**
	 * 列印錯誤日誌
	 * */
	public static void printErrMsg(Logger logger, String msg, Exception e){
		logger.error("^-^ " + msg + e.getMessage(), e);
	}
	
	/**
	 * 列印非錯誤日誌
	 * */
	public static void printTrackingMsg(Logger logger, String msg){
		logger.info("^.^ " + msg);
	}
}
宣告式事務配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

	<!-- <import resource="applicationContext-activiti.xml"/> -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>
	<!-- 註解方式配置事物 -->
	<!-- <aop:config> <aop:advisor id="managerTx" advice-ref="txAdvice" pointcut="execution(**..service..*.*(..))" order="1"/> </aop:config> -->
	
	<aop:config>
		<aop:pointcut expression="(execution(* com.a.service.*.* (..))) or (execution(* com.b.service.*.* (..))) or (execution(* com.c.service.*.* (..)))" id="pointcut" />
		<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" />
	</aop:config>

	<!-- 事務控制 -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<!--只讀,開啟預設事務-->
			<tx:method name="get*" read-only="true" />
			
			<tx:method name="save*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
			……
			<tx:method name="crud*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
			……
			<!-- 此配置未測試是否存在 -->
			<tx:method name="*" />
			
			<!--此字首只讀,非事務方式執行方法-->
			<tx:method name="notSupport*" propagation="NOT_SUPPORTED" read-only="true" />
		</tx:attributes>
	</tx:advice>
</beans>
好了,各個sheet也作為事務單元處理,1,2,3解析,2失敗(事務失敗),1,3成功進入資料庫。