springboot 同一方法内,多数据源切换,包含事务

最近项目遇到了同一方法内,主数据库操作数据后,需往其他数据源同步数据的情景,在此记录一下实现过程,也参照了下其他大牛的代码

主要有两种实现方式

  1. 通过主动方式切换数据源
  2. 直接获取JdbcTemplate

参考文章:
SpringBoot多数据源切换详解,以及开启事务后数据源切换失败处理
springboot+mybatis解决多数据源切换事务控制不生效的问题

一、禁用数据库自动配置

禁用数据库自动配置需在Application类上增加配置,可在@SpringBootApplication注解后,也可在@EnableAutoConfiguration注解后配置。

@SpringBootApplication(exclude={
   
   DataSourceAutoConfiguration.class})@EnableAutoConfiguration(exclude={
   
   DataSourceAutoConfiguration.class})

有时也需要屏蔽如下类:

DataSourceTransactionManagerAutoConfiguration.class
JdbcTemplateAutoConfiguration.class
HibernateJpaAutoConfiguration.class

二、主动切换数据源方式

2.1 配置数据源类型

通常采用常量或者枚举类型

public enum  DBType {
   
   
    
    one("one"),

    two("two");

    private String value;

    DBType(String value) {
   
   
        this.value = value;
    }

    public String getValue() {
   
   
        return value;
    }
}

2.2 配置数据源切换上下文

public class DBContextHolder {
   
   
    private static final ThreadLocal contextHolder = new ThreadLocal<>();
    /**
     * 设置数据源
     * @param DBType
     */
    public static void setDbType(DBType dbType) {
   
   
        contextHolder.set(dbType.getValue());
    }

    /**
     * 取得当前数据源
     * @return
     */
    public static String getDbType() {
   
   
        return (String) contextHolder.get();
    }

    /**
     * 清除上下文数据
     */
    public static void clearDbType() {
   
   
        contextHolder.remove();
    }
}

2.3 配置动态切换数据源类

需要继承AbstractRoutingDataSource类,并重写determineCurrentLookupKey()方法,从数据源类型中获取当前线程的数据源类型。

public class DynamicDataSource extends AbstractRoutingDataSource  {
   
   

    @Override
    protected Object determineCurrentLookupKey() {
   
   
        return  DBContextHolder.getDbType();
    }
}

2.4 重写Transaction

当我们配置了事物管理器和拦截Service中的方法后,每次执行Service中方法前会开启一个事务,并且同时会缓存一些东西:DataSource、SqlSessionFactory、Connection等,所以,我们在外面再怎么设置要求切换数据源也没用,因为Conneciton都是从缓存中拿的,所以我们要想能够顺利的切换数据源,实际就是能够动态的根据DatabaseType获取不同的Connection,并且要求不能影响整个事物的特性。

主要包含两个类:

import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import org.apache.ibatis.transaction.Transaction;
import org.springframework.jdbc.CannotGetJdbcConnectionException;
import org.springframework.jdbc.datasource.DataSourceUtils;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import static org.apache.commons.lang3.Validate.notNull;

/**
* <P>多数据源切换,支持事务</P>
*
* @author 高仕立
* @date 2018/2/6 9:09
* @since
*/
public class MultiDataSourceTransaction implements Transaction{
   
   
   private static final Log LOGGER = LogFactory.getLog(MultiDataSourceTransaction.class);

   private final DataSource dataSource;

   private Connection mainConnection;

   private String mainDatabaseIdentification;

   private ConcurrentMap<String, Connection> otherConnectionMap;


   private boolean isConnectionTransactional;

   private boolean autoCommit;


   public MultiDataSourceTransaction(DataSource dataSource) {
   
   
       notNull(dataSource, "No DataSource specified");
       this.dataSource = dataSource;
       otherConnectionMap <
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值