在一个事务中使用多线程操作数据库时,若同时存在对数据库的读写操作,可能出现数据读取的不准确,因为多线程将不会共享同一个事务(也就是说子线程和主线程的事务不一样),为了解决这个问题,可以使用spring的分布式事务jta,并重写JtaTransactionManager的doCommit和doRollback方法。

1、引入maven依赖

<dependency>
            <groupId>com.atomikos</groupId>
            <artifactId>transactions-jdbc</artifactId>
            <version>3.9.3</version>
        </dependency>
        <dependency>
            <groupId>javax.transaction</groupId>
            <artifactId>jta</artifactId>
            <version>1.1</version>
        </dependency> 

2、配置xml文件

<!-- atomikos事务管理器 -->
    <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
        init-method="init" destroy-method="close">
        <description>UserTransactionManager</description>
        <property name="forceShutdown">
            <value>true</value>
        </property>
    </bean>

    <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
        <property name="transactionTimeout" value="3000" />
    </bean>

    <!-- spring 事务管理器,必须使用二次开发的类,控制solr的回滚 -->
    <bean id="springTransactionManager"
        class="com.yzh.core.inner.impl.SepJtaTransactionManager">
        <property name="transactionManager">
            <ref bean="atomikosTransactionManager" />
        </property>
        <property name="userTransaction">
            <ref bean="atomikosUserTransaction" />
        </property>
        <!-- 必须设置,否则程序出现异常 JtaTransactionManager does not support custom isolation levels by default -->
        <property name="allowCustomIsolationLevels" value="true"/>
    </bean>

     <!-- 开启注解事务定义,由Spring扫描注解定义的事务 -->
    <tx:annotation-driven transaction-manager="springTransactionManager" proxy-target-class="true" />

3、将一些查询数据库的操作放到容器里面,在事务提交的时候执行

public class ContextKeeper {
private static final ThreadLocal<Collection<Runnable>> keepAfterSubmit = new ThreadLocal<>();

  //将需要执行的多线程放到容器中
    public static void put(Collection<Runnable> tasks) {
        keepAfterSubmit.set(tasks);
    }    //获取并移除容器中的任务
    public static Collection<Runnable> getAndRemoveSubmitTask() {
        synchronized (keepAfterSubmit) {
            Collection<Runnable> tasks = keepAfterSubmit.get();
            keepAfterSubmit.remove();
            return tasks;
        }
    }
  //移除容器中的任务
    public static void removeSubmitTask() {
        synchronized (keepAfterSubmit) {
            keepAfterSubmit.remove();
        }
    }

4、重写JtaTransactionManager的doCommit和doRollback方法。

public class SepJtaTransactionManager extends JtaTransactionManager {

    /**
     *
     */
    private static final long serialVersionUID = -1468472287996669189L;
    private static final Logger LOGGER = LoggerDeputyUtil.getSelfClassLogger();

    @Override
    protected void doCommit(DefaultTransactionStatus status) {
        super.doCommit(status);// 执行后续任务
        Collection<Runnable> tasks = ContextKeeper.getAndRemoveSubmitTask();
        if (!JudgeUtil.isEmpty(tasks)) {
            LOGGER.info("执行后续任务");
            try {
                ExecutorService pool = CommonHelper.pool();
                for (Runnable task : tasks) {
                    pool.submit(task);
                }
            } catch (Exception e) {
                ErrorLevel.LOG_HANDLERHIS_FAIL.doLog("执行后续任务失败", e);
            }
        }
    }

    @Override
    protected void doRollback(DefaultTransactionStatus status) {
        super.doRollback(status);// 清空任务
        ContextKeeper.removeSubmitTask();
    }
}

解决spring多线程不共享事务的问题的更多相关文章

  1. spring 多线程 注入 服务层 问题

    在用多线程的时候,里面要用到Spring注入服务层,或者是逻辑层的时候,一般是注入不进去的.具体原因应该是线程启动时没有用到Spring实例不池.所以注入的变量值都为null. 详细:http://h ...

  2. spring中注解式事务不生效的问题

    常用的解决方法可以百度,我针对我的问题描述一下 Mysql中InnoDB引擎才支持事务, MyISAM不支持事务. 当你尝试了各种方法解决spring中注解式事务不生效时, 一定要查看一下数据库中表的 ...

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

    原文:http://blog.csdn.net/c289054531/article/details/9196053 引言:     在使用Spring时,很多人可能对Spring中为什么DAO和Se ...

  4. spring学习 8-面试(事务,解决线程安全)

    1.介绍一下Spring的事物管理 参考:Spring 学习7 -事务 2.Spring如何处理线程并发问题    Spring使用ThreadLocal解决线程安全问题 参考:Spring学习11- ...

  5. Spring笔记(4) - Spring的编程式事务和声明式事务详解

    一.背景 事务管理对于企业应用而言至关重要.它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性.就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到操作 ...

  6. 全面分析 Spring 的编程式事务管理及声明式事务管理

    开始之前 关于本教程 本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本 ...

  7. JAVA多线程之间共享数据BlockingQueue介绍

    在JAVA的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题.通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大的便利. ...

  8. 解决spring配置中的bean类型的问题:BeanNotOfRequiredTypeException

    解决spring配置中的bean类型的问题:BeanNotOfRequiredTypeException这个问题出现的原因:一般在使用annotation的方式注入spring的bean 出现的,具体 ...

  9. spring的annotation-driven配置事务管理器详解

    http://blog.sina.com.cn/s/blog_8f61307b0100ynfb.html ——————————————————————————————————————————————— ...

随机推荐

  1. 为什么matlab激活完后还要激活(Matlab2012b license失效解决办法)

    第一步:打开matlab安装路径中的license文件夹,删除其中的lic文件 第二步:更换新的license.lic文件 第三步:重新打开matlab 搞定! license.lic文件的内容是: ...

  2. hyperledger中文文档学习-2-简介

    参考https://hyperledgercn.github.io/hyperledgerDocs/blockchain_zh/ Hyperledger区块链框架(https://blog.csdn. ...

  3. day12--装饰器

    定义(如何理解装饰器):装饰器本生是闭包函数的一种应用,是指在不改变原函数的情况下为原函数添加新的功能的一个函数.它把被装饰的函数作为外层函数的参数传入装饰器,通过闭包操作后返回一个替代版函数. 遵循 ...

  4. day07----字符编码解码、文件操作(1)

    字符编码: 什么是字符编码? 字符编码是将人识别的字符转换成计算机能识别的二进制字符(01),转换的规则就是编码表. 人能识别的字符串  与  计算机能识别的二进制字符 两者之间对应关系构成的结构称为 ...

  5. RabbitMQ详解(三)------RabbitMQ的五种队列

    上一篇博客我们介绍了RabbitMQ消息通信中的一些基本概念,这篇博客我们介绍 RabbitMQ 的五种工作模式,这也是实际使用RabbitMQ需要重点关注的. 这里是RabbitMQ 官网中的相关介 ...

  6. Python股票分析系列——基础股票数据操作(二).p4

    该系列视频已经搬运至bilibili: 点击查看 欢迎来到Python for Finance教程系列的第4部分.在本教程中,我们将基于Adj Close列创建烛台/ OHLC图,这将允许我介绍重新采 ...

  7. Item 13: 比起iterator优先使用const_iterator

    本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 STL中的const_iterator等价于pointers-to ...

  8. urllib爬虫(流程+案例)

    网络爬虫是一种按照一定规则自动抓取万维网信息的程序.在如今网络发展,信息爆炸的时代,信息的处理变得尤为重要.而这之前就需要获取到数据.有关爬虫的概念可以到网上查看详细的说明,今天在这里介绍一下使用ur ...

  9. flink1.7自定义source实现

    flink读取source data 数据的来源是flink程序从中读取输入的地方.我们可以使用StreamExecutionEnvironment.addSource(sourceFunction) ...

  10. 十九、多文件上传(ajaxFileupload实现多文件上传功能)

    来源于https://www.jb51.net/article/128647.htm 打开google 搜索"ajaxFileupload' ‘多文件上传"可以搜到许许多多类似的, ...