spring中事务传播下,特殊方法手动控制事务

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 在开发中,遇到事务问题:从excel文件中解析导入数据,每个sheet页中的数据作为单个的事务单元提交数据库。解析下代码实现: 方法①:mainAnalysisEntrance(…)解析excel入口和权限和其他业务等处理; 方法②:analysisWorkbook(…)解析excel工作簿; 方法③:analysisPerSheet(…)解析每一个sheet页数据,并将其中通过的数

在开发中,遇到事务问题:从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成功进入数据库。


目录
相关文章
|
19天前
|
Java 开发者 Spring
Spring高手之路24——事务类型及传播行为实战指南
本篇文章深入探讨了Spring中的事务管理,特别是事务传播行为(如REQUIRES_NEW和NESTED)的应用与区别。通过详实的示例和优化的时序图,全面解析如何在实际项目中使用这些高级事务控制技巧,以提升开发者的Spring事务管理能力。
33 1
Spring高手之路24——事务类型及传播行为实战指南
|
12天前
|
XML Java 数据库连接
Spring中的事务是如何实现的
Spring中的事务管理机制通过一系列强大的功能和灵活的配置选项,为开发者提供了高效且可靠的事务处理手段。无论是通过注解还是AOP配置,Spring都能轻松实现复杂的事务管理需求。掌握这些工具和最佳实践,能
19 3
|
26天前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
31 1
|
1月前
|
存储 安全 Java
|
27天前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
27 1
|
2月前
|
Java 数据库连接 数据库
spring复习05,spring整合mybatis,声明式事务
这篇文章详细介绍了如何在Spring框架中整合MyBatis以及如何配置声明式事务。主要内容包括:在Maven项目中添加依赖、创建实体类和Mapper接口、配置MyBatis核心配置文件和映射文件、配置数据源、创建sqlSessionFactory和sqlSessionTemplate、实现Mapper接口、配置声明式事务以及测试使用。此外,还解释了声明式事务的传播行为、隔离级别、只读提示和事务超时期间等概念。
spring复习05,spring整合mybatis,声明式事务
|
24天前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
22 0
|
1月前
|
Java 关系型数据库 MySQL
Spring事务失效,我总结了这7个主要原因
本文详细探讨了Spring事务在日常开发中常见的七个失效原因,包括数据库不支持事务、类不受Spring管理、事务方法非public、异常被捕获、`rollbackFor`属性配置错误、方法内部调用事务方法及事务传播属性使用不当。通过具体示例和源码分析,帮助开发者更好地理解和应用Spring事务机制,避免线上事故。适合所有使用Spring进行业务开发的工程师参考。
32 2
|
1月前
|
Java 程序员 Spring
Spring事务的1道面试题
每次聊起Spring事务,好像很熟悉,又好像很陌生。本篇通过一道面试题和一些实践,来拆解几个Spring事务的常见坑点。
Spring事务的1道面试题
|
2月前
|
Java Spring
Spring 事务传播机制是什么?
Spring 事务传播机制是什么?
23 4
下一篇
无影云桌面