Spring事务与自定义多线程陷阱

场景: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<Integer> 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.setExtraInfo("");
				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;
    }
时间: 2024-10-18 04:23:05

Spring事务与自定义多线程陷阱的相关文章

Spring单实例、多线程安全、事务解析

原文:http://blog.csdn.net/c289054531/article/details/9196053 引言: 在使用Spring时,很多人可能对Spring中为什么DAO和Service对象采用单实例方式很迷惑,这些读者是这么认为的: DAO对象必须包含一个数据库的连接Connection,而这个Connection不是线程安全的,所以每个DAO都要包含一个不同的Connection对象实例,这样一来DAO对象就不能是单实例的了. 上述观点对了一半.对的是“每个DAO都要包含一个

spring事务管理器设计思想(一)

首先堆栈和堆(托管堆)都在进程的虚拟内存中.(在32位处理器上每个进程的虚拟内存为4GB) 堆栈stack 1.堆栈中存储值类型 2.堆栈实际上是向下填充,即由高内存地址指向低内存地址填充 3.堆栈的工作方式是先分配内存的变量后释放(先进后出原则) 4.堆栈中的变量是从下向上释放,这样就保证了堆栈中先进后出的规则不与变量的生命周期起冲突 5.堆栈的性能非常高,但是对于所有的变量来说还不灵活,而且变量的生命周期必须嵌套. 6.通常我们希望使用一种方法分配内存来存储数据,并且方法退出后很长一段时间内

手写 Spring 事务、IOC、DI 和 MVC

Spring AOP 原理 什么是 AOP? AOP 即面向切面编程,利用 AOP 可以对业务进行解耦,提高重用性,提高开发效率 应用场景:日志记录,性能统计,安全控制,事务处理,异常处理 AOP 底层实现原理是采用代理实现的 Spring 事务 基本特性: 原子性 隔离性 一致性 持久性 事务控制分类: 编程式事务:手动控制事务操作 声明式事务:通过 AOP 控制事务 编程式事务实现 使用编程事务实现手动事务 @Component @Scope("prototype") public

Spring 事务管理高级应用难点剖析--转

第 1 部分 http://www.ibm.com/search/csass/search/?q=%E4%BA%8B%E5%8A%A1&sn=dw&lang=zh&cc=CN&en=utf&hpp=20&dws=cndw&lo=zh 概述 Spring 最成功,最吸引人的地方莫过于轻量级的声明式事务管理,仅此一点,它就宣告了重量级 EJB 容器的覆灭.Spring 声明式事务管理将开发者从繁复的事务管理代码中解脱出来,专注于业务逻辑的开发上,这是一件

Spring事务管理源码分析

Spring事务管理方式 依据Spring.xsd文件可以发现,Spring提供了advice,annotation-driven,jta-transaction-manager3种事务管理方式.详情可查看相应版本xsd文件.这里参照的版本是3.2.我们也只分析advice方式的源码,期望以此为突破口了解Spring事务管理的原理. Advice事务管理 XSD文件 我们先来看下xsd文件的配置 <xsd:element name="advice"> <xsd:com

spring事务管理——编程式事务、声明式事务

本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本教程假定您已经掌握了 Java 基础知识,并对 Spring 有一定了解.您还需要具备基本的事务管理的知识,比如:事务的定义,隔离级别的概念,等等.本文将直接使用这些概念而不做详细解释.另外,您最好掌握数据库的基础知识,虽然这不是必须. 系统需求 要试验这份教程中的工具和示例,硬件配置需求为:至少带有 512MB 内存(

结合ThreadLocal来看spring事务源码,感受下清泉般的洗涤!

在我的博客spring事务源码解析中,提到了一个很关键的点:将connection绑定到当前线程来保证这个线程中的数据库操作用的是同一个connection.但是没有细致的讲到如何绑定,以及为什么这么绑定:另外也没有讲到连接池的相关问题:如何从连接池获取,如何归还连接到连接池等等.那么下面就请听我慢慢道来. ThreadLocal 讲spring事务之前,我们先来看看ThreadLocal,它在spring事务中是占据着比较重要的地位:不管你对ThreadLocal熟悉与否,且都静下心来听我唐僧

Spring事务管理实现原理及MySQL InnoBD引擎行锁概述

Spring实现事务管理的机制 Spring事务管理是基于AOP编程思想实现,Spring框架被广泛使用的原因之一,就是提供了强大的事务管理机制. AOP是什么?我们常说的AOP并不是指一种开发技术,而是一种编程思想,AOP的核心概念就是面向切面编程,实现可插拔,降低程序之前的耦合性,提高重用性. Spring AOP 基于动态代理实现,一种是JDK动态代理,另一种是CGLIB动态代理. spring2.5之前声明式事务可以这样实现: ?<!-- 声明使用的spring事务管理器--> <

Spring事务隔离级别与传播机制,spring+mybatis+atomikos实现分布式事务管理

本文转载于本人另一博客[http://blog.csdn.net/liaohaojian/article/details/68488150] 1.事务的定义:事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,要么都成功.其必须遵循四个原则(ACID). 原子性(Atomicity):即事务是不可分割的最小工作单元,事务内的操作要么全做,要么全不做: 一致性(Consistency):在事务执行前数据库的数据处于正确的状态,而事务执行完成后数据库的数据还是应该处于正确