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

标签: spring 定义 多线程 | 发表时间:2015-04-09 00:04 | 作者:thjnemo
出处:http://blog.csdn.net

        场景: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;
    }


作者:thjnemo 发表于2015/4/8 16:04:18 原文链接
阅读:14 评论:0 查看评论

相关 [spring 定义 多线程] 推荐:

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

- - CSDN博客推荐文章
        场景:Spring+Ibatis环境,使用spring aop事务(配置到service层),在一个service方法中,自定义了一个多线程,结果事务不起作用了,不用线程,则事务有效.         原因:Spring的事务是通过ThreadLocal来保证线程安全的,事务和当前线程绑定,所以自己开了多线程自然会让事务失效.

Spring MVC 创建自定义转换器

- - 开源软件 - ITeye博客
         我们在使用SpringMVC时,常常需要把表单中的参数映射到我们对象的属性中,我们可以在默认的spring-servlet.xml加上如下的配置即可做到普通数据类型的转换,如将String转换成Integer和Double等:.           其实  标签会默认创建并注册一个 RequestMappingHandlerMapping(在Spring3.2之前是DefaultAnnotationHandlerMapping) 和.

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

- - zzm
 在使用Spring时,很多人可能对Spring中为什么DAO和Service对象采用单实例方式很迷惑,这些读者是这么认为的:.     DAO对象必须包含一个数据库的连接Connection,而这个Connection不是线程安全的,所以每个DAO都要包含一个不同的Connection对象实例,这样一来DAO对象就不能是单实例的了.

Spring 框架笔记—4.16.2 标准与自定义事件

- - 企业架构 - ITeye博客
            Spring 框架笔记—4.16.2 标准与自定义事件. If a bean that implements the ApplicationListener interface is deployed into the context, every time an ApplicationEvent gets published to the ApplicationContext, that bean is notified.

为你 Spring Boot 项目自定义一个通用的异常

- - IT瘾-dev
本文出自《Springboot》专题系列. 我们的项目通常来讲都是一个比较大的项目,包含了各种各样的服务. 如果每个服务都以不同的方式返回异常信息,这样排查的时候就会比较凌乱. 如果我们定义一个标准的异常处理体系. 本文开发环境基于springboot2.4,IDE环境是IDEA. 逐步过渡到完全自定义自己的异常.

Spring详解

- - CSDN博客架构设计推荐文章
Spring是一个开源的控制反转(Inversion of Control ,IoC)和面向切面(AOP)的容器框架.它的主要目的是简化企业开发.. PersonDaoBean 是在应用内部创建及维护的. 所谓控制反转就是应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器负责的.

Spring定时

- - 行业应用 - ITeye博客
spring的定时任务配置分为三个步骤:. . . . . .

简单Spring+hessian

- - Web前端 - ITeye博客
简单的Spring+hessian. dist\modules里面的 spring-webmvc.jar . lib\caucho 里面的hessian-3.1.3.jar. 里面有个接口interface:. 建立一个model层:(实现Serializable接口). 在WEB-INF下面创建一个remoting-servlet.xml:.

Spring MVC 和 Struts2

- - CSDN博客架构设计推荐文章
Web层面的框架学习了三个Struts1和2,SpringMVC,那他们之间肯定存在一个优劣和适用的环境,Struts1和2的异同点我已经做过对比《 Struts1和Struts2》,这篇将对比下Struts2和SpringMVC的异同,下面数据基本来源于网络,本人是搜集整理所得,供大家参考. 一个项目使用什么样的技术,决定的因素很多,我所能想到的有:对系统的性能、开发的效率、团队学习的成本、业务场景等,下面尽量从这几个方面入手,来分析比较下他们之间存在的优劣.

Spring AOP详解

- - Java - 编程语言 - ITeye博客
        最近项目中遇到了以下几点需求,仔细思考之后,觉得采用AOP来解决. 一方面是为了以更加灵活的方式来解决问题,另一方面是借此机会深入学习Spring AOP相关的内容. 例如,以下需求不用AOP肯定也能解决,至于是否牵强附会,仁者见仁智者见智. 1.对部分函数的调用进行日志记录,用于观察特定问题在运行过程中的函数调用情况.