在一个事务中使用多线程操作数据库时,若同时存在对数据库的读写操作,可能出现数据读取的不准确,因为多线程将不会共享同一个事务(也就是说子线程和主线程的事务不一样),为了解决这个问题,可以使用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. mybatis error

    2018-08-02 14:01:18.021 WARN org.apache.catalina.loader.WebappClassLoaderBase Line:179 - The web app ...

  2. 004_centos安装pip的几种方式及pip源

    一. (1) yum -y install epel-release yum install python-pip pip install --upgrade pip (2) python脚本的一键安 ...

  3. Python2 处理 Unicode 字符串的规则

    在 Python2 中处理 Unicode 字符串,需遵循如下规则: 1. 程序中的字符串要加前缀 u 2. 不要用 str(),而应该用 unicode() 作为字符串转换函数.不要使用 chr() ...

  4. Spring Security(六):2.3 Release Numbering

    It is useful to understand how Spring Security release numbers work, as it will help you identify th ...

  5. CF1083E The Fair Nut and Rectangles

    CF1083E The Fair Nut and Rectangles 给定 \(n\) 个平面直角坐标系中左下角为坐标原点,右上角为 \((x_i,\ y_i)\) 的互不包含的矩形,每一个矩形拥有 ...

  6. 工具篇-Json处理

    1. @JsonProperty和@SerializedName注解 使用场景 将一个json格式的字符串转换成某个java对象,或者将一个java对象转换成json格式的字符串时,如果json字符串 ...

  7. mongo索引命令

    http://blog.csdn.net/salmonellavaccine/article/details/53907535 1. 创建/重建索引 MongoDB全新创建索引使用ensureInde ...

  8. 【php增删改查实例】第二十五节 - 在main.php中显示头像

    在用户成功上传头像以后,用户登录系统,应该能够看到自己的头像,本节演示如何在这个地方: 添加用户头像. 1.用DIV做: border-radius:50% background:url(xxx.jp ...

  9. xampp 使用过程中刚遇到的问题记录

    开始使用XAMPP的时候,都是可以正常连接的,但是过一段时间后,在用它创建表或其他操作,会报错,提示如下错误 Access denied for user ''@'localhost' to data ...

  10. 了解可执行的NPM包

    NPM是Node.js的包管理工具,随着Node.js的出现,以及前端开发开始使用gulp.webpack.rollup以及其他各种优秀的编译打包工具(大多数采用Node.js来实现),大家都开始接触 ...