Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 2906|回复: 0

spring多数据源分布式事务的分析与解决方案

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-4-6 17:37:14 | 显示全部楼层 |阅读模式

    一、概述

      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配置

      

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-17 01:04 , Processed in 0.070606 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表