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

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


目录
相关文章
|
2月前
|
SQL Java 关系型数据库
Spring事务传播机制:7种姿势教你玩转"事务接力赛"
事务传播机制是Spring框架中用于管理事务行为的重要概念,它决定了在方法调用时事务如何传递与执行。通过7种传播行为,开发者可以灵活控制事务边界,适应不同业务场景。例如:REQUIRED默认加入或新建事务,REQUIRES_NEW独立开启新事务,NESTED支持嵌套回滚等。合理使用传播机制不仅能保障数据一致性,还能提升系统性能与健壮性。掌握这“七种人格”,才能在复杂业务中游刃有余。
|
3月前
|
Java 关系型数据库 数据库
深度剖析【Spring】事务:万字详解,彻底掌握传播机制与事务原理
在Java开发中,Spring框架通过事务管理机制,帮我们轻松实现了这种“承诺”。它不仅封装了底层复杂的事务控制逻辑(比如手动开启、提交、回滚事务),还提供了灵活的配置方式,让开发者能专注于业务逻辑,而不用纠结于事务细节。
|
8月前
|
Java Spring
Spring中事务失效的场景
因为Spring事务是基于代理来实现的,所以某个加了@Transactional的⽅法只有是被代理对象调⽤时, 那么这个注解才会⽣效 , 如果使用的是被代理对象调用, 那么@Transactional会失效 同时如果某个⽅法是private的,那么@Transactional也会失效,因为底层cglib是基于⽗⼦类来实现 的,⼦类是不能重载⽗类的private⽅法的,所以⽆法很好的利⽤代理,也会导致@Transactianal失效 如果在业务中对异常进行了捕获处理 , 出现异常后Spring框架无法感知到异常, @Transactional也会失效
|
8月前
|
Java 关系型数据库 数据库
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——常见问题总结
本文总结了Spring Boot中使用事务的常见问题,虽然通过`@Transactional`注解可以轻松实现事务管理,但在实际项目中仍有许多潜在坑点。文章详细分析了三个典型问题:1) 异常未被捕获导致事务未回滚,需明确指定`rollbackFor`属性;2) 异常被try-catch“吃掉”,应避免在事务方法中直接处理异常;3) 事务范围与锁范围不一致引发并发问题,建议调整锁策略以覆盖事务范围。这些问题看似简单,但一旦发生,排查难度较大,因此开发时需格外留意。最后,文章提供了课程源代码下载地址,供读者实践参考。
164 0
|
8月前
|
Java 关系型数据库 数据库
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——Spring Boot 事务配置
本文介绍了 Spring Boot 中的事务配置与使用方法。首先需要导入 MySQL 依赖,Spring Boot 会自动注入 `DataSourceTransactionManager`,无需额外配置即可通过 `@Transactional` 注解实现事务管理。接着通过创建一个用户插入功能的示例,展示了如何在 Service 层手动抛出异常以测试事务回滚机制。测试结果表明,数据库中未新增记录,证明事务已成功回滚。此过程简单高效,适合日常开发需求。
1053 0
|
8月前
|
Java 数据库 微服务
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——事务相关
本文介绍Spring Boot事务配置管理,阐述事务在企业应用开发中的重要性。事务确保数据操作可靠,任一异常均可回滚至初始状态,如转账、购票等场景需全流程执行成功才算完成。同时,事务管理在Spring Boot的service层广泛应用,但根据实际需求也可能存在无需事务的情况,例如独立数据插入操作。
192 0
|
6月前
|
人工智能 Java 数据库连接
Spring事务失效场景
本文深入探讨了Spring框架中事务管理可能失效的几种常见场景及解决方案,包括事务方法访问级别不当、方法内部自调用、错误的异常处理、事务管理器或数据源配置错误、数据库不支持事务以及不合理的事务传播行为或隔离级别。通过合理配置和正确使用`@Transactional`注解,开发者可以有效避免这些问题,确保应用的数据一致性和完整性。
279 10
|
5月前
|
Java 关系型数据库 MySQL
【Spring】【事务】初学者直呼学会了的Spring事务入门
本文深入解析了Spring事务的核心概念与使用方法。Spring事务是一种数据库事务管理机制,通过确保操作的原子性、一致性、隔离性和持久性(ACID),维护数据完整性。文章详细讲解了声明式事务(@Transactional注解)和编程式事务(TransactionTemplate、PlatformTransactionManager)的区别与用法,并探讨了事务传播行为(如REQUIRED、REQUIRES_NEW等)及隔离级别(如READ_COMMITTED、REPEATABLE_READ)。
399 1
|
7月前
|
缓存 安全 Java
深入解析HTTP请求方法:Spring Boot实战与最佳实践
这篇博客结合了HTTP规范、Spring Boot实现和实际工程经验,通过代码示例、对比表格和架构图等方式,系统性地讲解了不同HTTP方法的应用场景和最佳实践。
636 5
|
7月前
|
Java Spring 容器
两种Spring Boot 项目启动自动执行方法的实现方式
在Spring Boot项目启动后执行特定代码的实际应用场景中,可通过实现`ApplicationRunner`或`CommandLineRunner`接口完成初始化操作,如系统常量或配置加载。两者均支持通过`@Order`注解控制执行顺序,值越小优先级越高。区别在于参数接收方式:`CommandLineRunner`使用字符串数组,而`ApplicationRunner`采用`ApplicationArguments`对象。注意,`@Order`仅影响Bean执行顺序,不影响加载顺序。
530 2

热门文章

最新文章