热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Spring事务管理与自定义多线程开发中的潜在风险分析

在Spring与Ibatis集成的环境中,通过SpringAOP配置事务管理至服务层。当在一个服务方法中引入自定义多线程时,发现事务管理功能失效。若不使用多线程,事务管理则能正常工作。本文深入分析了这一现象背后的潜在风险,并探讨了可能的解决方案,以确保事务一致性和线程安全。

        场景:Spring+Ibatis环境,使用spring aop事务(配置到service层),在一个service方法中,自定义了一个多线程,结果事务不起作用了,不用线程,则事务有效。

        原因:Spring的事务是通过ThreadLocal来保证线程安全的,事务和当前线程绑定,所以自己开了多线程自然会让事务失效。

        Spring的事务管理器是通过ThreadLocal来保存每个线程的副本,从而实现线程安全的,再结合IoC和Aop实现高级声明式事务的功能,所以Spring的事务天然地和线程有着千丝万缕的联系。只能维护web应用的多线程,不支持多线程里的多线程。

        其他方案:修改代码架构,把逻辑处理部分抽出来,放在另外一个service中,然后通过xxx.service的方法去调用(在事务范围外做的线程操作),这样就有了事务。

        应用场景:对历史数据进行迭代处理,处理完成一条就添加到数据库,不成功则抛出异常(如果不使用多线程则可以做到一批数据要么全部成功,有一个失败就全部回滚)。


        代码片段如下:

        代码一ReclaimMatchSubscriptionServiceImpl、

private void saveHistoryMatches(final MatchedInfoParams params, final CommonTaskName taskName, final List matchIds) {
new Thread() {
@Override
public void run() {
MatchedInfoParams clOnedParams= params.clone();
for (final Integer matchId : matchIds) {
try {
clonedParams.setMatchId(matchId);
saveWorkingTask(clonedParams, taskName, TaskPriority.LOW);
} catch (Exception e) {
logger.error("Save history matches to working task failed: matchedId=" + matchId + ", companyId=" + params.getCompanyId() + ", taskName=" + taskName
+ ", matchType=" + params.getMatchType(), e);
}
}
}
}.start();
}

public void saveWorkingTask(T params, CommonTaskName taskName, TaskPriority priority) {
Assert.notNull(params, "CommonTaskParams must not be null");
Assert.notNull(taskName, "CommonTaskName must not be null");
Assert.notNull(priority, "TaskPriority must not be null");

if (isServiceToDeal(taskName)) {
String uniqueKey = new MD5().MD5(uniqueKey(params));
WorkingCommonTask oldTask = commonTaskService.getWorkingTaskByNameAndKey(taskName, uniqueKey);
if (isAddToWorkingTask(oldTask)) {
WorkingCommonTask task = new WorkingCommonTask();
task.setCompanyId(params.getCompanyId());
task.setTaskName(taskName.getCode());
task.setUniqueKey(uniqueKey);
task.setRetrievalField(retrievalField(params));
task.setRetryCount(0);
task.setTaskPriority(priority.getCode());
task.setTaskStatus(CommonTaskStatus.CREATED.getCode());
task.setTimeout(0);
commonTaskService.saveWorkingTask(task, getBiz(params));
}
}
}


        代码二CommonTaskServiceImpl、

public int saveWorkingTask(WorkingCommonTask workingTask, String bizData) {
Assert.notNull(workingTask, "workingTask must not be null");
Assert.notNull(bizData, "bizData must not be null");

if (workingTask.getTimeout() <= 0) {
workingTask.setTimeout(timeout);
}

int taskId = commonTaskDao.saveWorkingTask(workingTask);

CommonTaskExtraInfo taskExtraInfo = new CommonTaskExtraInfo();
taskExtraInfo.setTaskId(taskId);
taskExtraInfo.setBizData(bizData);
commonTaskDao.saveTaskExtraInfo(taskExtraInfo);

commonTaskDao.saveTaskLog(new CommonTaskLog(taskId, workingTask.getTaskStatus(), workingTask.getExtraInfo()));

return taskId;
}

另外,对于第一段代码事务失效,还有另外一种解释:

public class A {
@annotation
public B () {

}

public C () {
B();
}

}

当一个类中,方法B上面有注解(譬如:事务注解),方法B被方法C调用,当其他方法调用方法C的时候方法B上面的注解是无效的!


推荐阅读
  • 本文探讨了在SQL Server 2008环境下,当尝试删除拥有数据库架构的用户时遇到的问题及解决方案,包括如何查询和更改架构所有权。 ... [详细]
  • 本文介绍了SIP(Session Initiation Protocol,会话发起协议)的基本概念、功能、消息格式及其实现机制。SIP是一种在IP网络上用于建立、管理和终止多媒体通信会话的应用层协议。 ... [详细]
  • 如何在U8系统中连接服务器并获取数据
    本文介绍了如何在U8系统中通过不同的方法连接服务器并获取数据,包括使用MySQL客户端连接实例的方法,如非SSL连接和SSL连接,并提供了详细的步骤和注意事项。 ... [详细]
  • 软件测试行业深度解析:迈向高薪的必经之路
    本文深入探讨了软件测试行业的发展现状及未来趋势,旨在帮助有志于在该领域取得高薪的技术人员明确职业方向和发展路径。 ... [详细]
  • 问题描述现在,不管开发一个多大的系统(至少我现在的部门是这样的),都会带一个日志功能;在实际开发过程中 ... [详细]
  • 从理想主义者的内心深处萌发的技术信仰,推动了云原生技术在全球范围内的快速发展。本文将带你深入了解阿里巴巴在开源领域的贡献与成就。 ... [详细]
  • 本文介绍了ADO.NET框架中的五个关键组件:Connection、Command、DataAdapter、DataSet和DataReader。每个组件都在数据访问和处理过程中扮演着不可或缺的角色。 ... [详细]
  • 本文探讨了如何通过Service Locator模式来简化和优化在B/S架构中的服务命名访问,特别是对于需要频繁访问的服务,如JNDI和XMLNS。该模式通过缓存机制减少了重复查找的成本,并提供了对多种服务的统一访问接口。 ... [详细]
  • 本文将从基础概念入手,详细探讨SpringMVC框架中DispatcherServlet如何通过HandlerMapping进行请求分发,以及其背后的源码实现细节。 ... [详细]
  • Windows操作系统提供了Encrypting File System (EFS)作为内置的数据加密工具,特别适用于对NTFS分区上的文件和文件夹进行加密处理。本文将详细介绍如何使用EFS加密文件夹,以及加密过程中的注意事项。 ... [详细]
  • 本文探讨了在一个物理隔离的环境中构建数据交换平台所面临的挑战,包括但不限于数据加密、传输监控及确保文件交换的安全性和可靠性。同时,作者结合自身项目经验,分享了项目规划、实施过程中的关键决策及其背后的思考。 ... [详细]
  • 深入理解:AJAX学习指南
    本文详细探讨了AJAX的基本概念、工作原理及其在现代Web开发中的应用,旨在为初学者提供全面的学习资料。 ... [详细]
  • 流处理中的计数挑战与解决方案
    本文探讨了在流处理中进行计数的各种技术和挑战,并基于作者在2016年圣何塞举行的Hadoop World大会上的演讲进行了深入分析。文章不仅介绍了传统批处理和Lambda架构的局限性,还详细探讨了流处理架构的优势及其在现代大数据应用中的重要作用。 ... [详细]
  • 如何高效解决Android应用ANR问题?
    本文介绍了ANR(应用程序无响应)的基本概念、常见原因及其解决方案,并提供了实用的工具和技巧帮助开发者快速定位和解决ANR问题,提高应用的用户体验。 ... [详细]
  • PGXC中的两阶段提交机制及其对事务一致性的保障
    PGXC作为一款基于PostgreSQL的分布式数据库系统,利用Sharding技术将数据分散存储于多个数据库实例中。本文探讨了PGXC的两阶段提交过程及其实现事务强一致性的方法。 ... [详细]
author-avatar
讲述华哥传奇的生活_616
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有