zoukankan      html  css  js  c++  java
  • spring多数据源分布式事务的分析与解决方案

    一、概述

      1、业务背景

      对老系统进行重构合并,导致新系统需要同时对3个数据库进行管理。由于出现跨库业务,需要实现分布式事务。

      2、开发环境

      spring框架版本  4.3.10.RELEASE

      持久层为结合mybatis写的领域模型,如

      

      每一个entity对应数据库的一张表,@DataSource注解(自定义)了对应数据源的key值。所以一个业务中可能存在数据源的切换。

      事务采用注解@Transaction驱动。

    二、spring对多数据源的支持

      spring框架通过抽象类AbstractRoutingDataSource来实现多数据源支持。

      AbstractRoutingDataSource中有一个抽象方法determineCurrentLookupKey()。子类实现该方法即可。

      举例如下:

    package com.cmcc.cq.xx.common.mybatis;
    
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    
    public class DynamicDataSource extends AbstractRoutingDataSource {
    
    
        @Override
        protected Object determineCurrentLookupKey() {
            return getDataSourceType();
        }
    
        private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
    
        public static void setDataSourceType(String dataSourceType){
            contextHolder.set(dataSourceType);
        }
    
        public static String getDataSourceType(){
            return contextHolder.get();
        }
    
        public static void clearDataSourceType(){
            contextHolder.remove();
        }
    }

      ThreadLocal保存当前线程的数据源,执行数据库操作之前会通过解析注解@DataSource设置下次操作的数据源类型,即相应的key值(见后文数据源配置)。

      

      到此,在不使用事务的情况下,可以完成多数据源切换。

    三、spring分布式事务支持

      1、DataSourceTransactionManager不支持多数据源

      DataSourceTransactionManager事务管理器是一个单数据源事务管理器,在实例化时候会注入一个数据源。

    <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    	<property name="dataSource" ref="dynamicDataSource">
    	</property>
    </bean>

      注意:虽然我们注入的是一个动态数据源,但是DataSourceTransactionManager不会因为我们使用动态数据源而跟着变化。

      因为DataSourceTransactionManager开始事务时获取数据库connection时并不是每次都通过dataSource来获取,一般都是通过ConnectionHolder类获得。

      

      所以开启事务会报找不到表或视图的异常。

      同时DataSourceTransactionManager也不能实现跨库事务的一致性。

      2、JtaTransactionManager支持分布式事务

      JtaTransactionManager事务管理器只是提供一个接入方式,并没有做相应的实现,目前比较流行的分布式事务第三方实现是atomikos和jotm。其中jotm更新日期是2010年,建议使用atomikos。

      两者配置也是大同小异,以atomikos为例。

      引入maven依赖 

    <dependency>  
        <groupId>com.atomikos</groupId>  
        <artifactId>transactions-jdbc</artifactId>  
        <version>3.7.0</version>  
    </dependency>

      首先是数据源的配置,必须要使用类com.atomikos.jdbc.AtomikosDataSourceBean,不能再使用其他的连接池替代。xaDataSourceClassName要根据数据库选择相应的类,在数据库对应的驱动包里可以找到。

    <bean id="dataSource3" class="com.atomikos.jdbc.AtomikosDataSourceBean" destroy-method="close">  
    	    <property name="uniqueResourceName" value="key值"/>  
    	    <property name="xaDataSourceClassName" value="oracle.jdbc.xa.client.OracleXADataSource"/>  
    	    <property name="xaProperties">  
    	        <props>  
    	            <prop key="URL">${jdbc.dataSource.url3}</prop>  
    	            <prop key="user">${jdbc.dataSource.username3}</prop>  
    	            <prop key="password">${jdbc.dataSource.password3}</prop>  
    	        </props>  
    	    </property>  
    	    <property name="minPoolSize" value="${jdbc.dataSource.minimumIdle3}" />  
    	    <property name="maxPoolSize" value="${jdbc.dataSource.maximumPoolSize3}" />  
    	    <property name="borrowConnectionTimeout" value="${jdbc.dataSource.connectionTimeout3}" />  
    	    <property name="testQuery" value="${jdbc.dataSource.connectionTestQuery3}" />  
    	    <property name="maintenanceInterval" value="60" />  
    	    <property name="maxIdleTime" value="${jdbc.dataSource.idleTimeout3}"></property>
    </bean>

      然后是JtaTransactionManager事务管理器配置。

      JtaTransactionManager有两个重要属性需要配置transactionManager和userTransaction。对应的配置类如下:

      

      注:在jotm中只需配置transactionManager属性

      最后是atomikos的配置文件jta.properties。

      配置路径:根路径

      

      jta.properties也可命名为transactions.properties,如果不配置也可以启动项目,因为几乎所有配置项都有默认值。

      transactions.properties配置

      

    更多更好的原创https://blog.ccyws.cn
  • 相关阅读:
    Vue路由机制
    谷歌浏览器打不开应用商店的解决方法
    Vue报错——Component template should contain exactly one root element. If you are using vif on multiple elements, use velseif to chain them instead.
    Vue.js学习之——安装
    Vue使用axios无法读取data的解决办法
    关于localstorage存储JSON对象的问题
    2013年整体计划
    个人喜欢的警语收集
    Linux防火墙的关闭和开启
    Flex修改title 转载
  • 原文地址:https://www.cnblogs.com/qianjun2017/p/8349829.html
Copyright © 2011-2022 走看看