spring中事務傳播下,特殊方法手動控制事務
阿新 • • 發佈:2019-01-25
在開發中,遇到事務問題:從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); } }
好了,各個sheet也作為事務單元處理,1,2,3解析,2失敗(事務失敗),1,3成功進入資料庫。<?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>