springboot整合多数据源(mysql,impala)

springboot整合多数据源,这里以mysql和impala举例子

1.pom.xml

 <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

<dependency>
    <groupId>com.cloudera</groupId>
    <artifactId>ImpalaJDBC41</artifactId>
    <version>1.0</version>
</dependency>

<dependency>
   <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.9</version>
</dependency>

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency>

2.只需要把这个包下得代码复制过去即可

package com.hzy.work.database;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;


/**
* @Title DataSourceConfig
* @author  young_____hu
* @create  2020年05月16日
*/
@Configuration
@ConfigurationProperties(prefix = "spring.datasource.druid")
public class DataSourceConfig {
	
	private HashMap<String, HashMap<String, String>> ds = new HashMap<>();
    private HashMap<String, String> generalConfig = new HashMap<>();
    
    public HashMap<String, HashMap<String, String>> getDs() {
		return ds;
	}
	public void setDs(HashMap<String, HashMap<String, String>> ds) {
		this.ds = ds;
	}
	public HashMap<String, String> getGeneralConfig() {
		return generalConfig;
	}
	public void setGeneralConfig(HashMap<String, String> generalConfig) {
		this.generalConfig = generalConfig;
	}

	@Bean(name = "dynamicDataSource")
    public DynamicDataSource dataSource() throws Exception{
		
    	Object defaultDataSource = null;
        Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
        
        for (String name : ds.keySet()) {
            HashMap<String, String> dbConfig = ds.get(name);
			
            dbConfig.putAll(generalConfig);
			DataSource dataSource = DruidDataSourceFactory.createDataSource(dbConfig);
			
			if (name.equals("default")) {
			    defaultDataSource = dataSource;
			} else {
				targetDataSources.put(name, dataSource);
				DynamicDataSourceContextHolder.dataSourceIds.add(name);
			}
        }
        
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(defaultDataSource);
        return dynamicDataSource;
    }
	
}

package com.hzy.work.database;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * @Title DataSourceConfig
 * @author  young_____hu
 * @create  2020年05月16日
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

	@Override
	protected Object determineCurrentLookupKey() {
		 /*
         * DynamicDataSourceContextHolder代码中使用setDataSourceType
         *设置当前的数据源,在路由类中使用getDataSourceType进行获取,
         * 交给AbstractRoutingDataSource进行注入使用。
         */
        return DynamicDataSourceContextHolder.getDataSourceType();
	}

}

package com.hzy.work.database;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * @Title DataSourceConfig
 * @author  young_____hu
 * @create  2020年05月16日
 * 切换数据源Advice
 */

@Aspect
@Component
public class DynamicDataSourceAspect {
	
	@Pointcut("execution(public * com.hzy.work.*.*(..))")
    public void changeDataSource() {}  
	
	@Before("@annotation(targetDataSource)")
	public void changeDataSource(JoinPoint point, TargetDataSource targetDataSource) {
        DynamicDataSourceContextHolder.setDataSourceType(targetDataSource.value());
   }

	@After("@annotation(targetDataSource)")
	public void restoreDataSource(JoinPoint point, TargetDataSource targetDataSource) {
		//方法执行完毕之后,销毁当前数据源信息,进行垃圾回收。
		DynamicDataSourceContextHolder.clearDataSourceType();
	}
}

package com.hzy.work.database;

import java.util.ArrayList;
import java.util.List;

/**
 * @Title DataSourceConfig
 * @author  young_____hu
 * @create  2020年05月16日
 */
public class DynamicDataSourceContextHolder {

	/*

     *当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,

     *所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

     */

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
    /*

     *管理所有的数据源id;

     *主要是为了判断数据源是否存在;

     */

    public static List<String> dataSourceIds =new ArrayList<String>();

    /**
     *使用setDataSourceType设置当前的
     *@param dataSourceType
     */

    public static void setDataSourceType(String dataSourceType) {
           contextHolder.set(dataSourceType);
    }

    public static String getDataSourceType() {
           return contextHolder.get();
    }

    public static void clearDataSourceType() {
           contextHolder.remove();
    }
    
    /**

     *判断指定DataSrouce当前是否存在
     *@param dataSourceId
     *@return
     */

    public static boolean containsDataSource(String dataSourceId){
         return dataSourceIds.contains(dataSourceId);
    }
}

package com.hzy.work.database;

import org.apache.ibatis.transaction.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;

/**
 * @Title DataSourceConfig
 * @author  young_____hu
 * @create  2020年05月16日
 */
public class MultiDataSourceTransaction implements Transaction {

	private static final Logger LOGGER = LoggerFactory.getLogger(MultiDataSourceTransaction.class);
	  
    private final DataSource dataSource;  
  
    private Connection mainConnection;  
  
    private ConcurrentMap<String, Connection> otherConnectionMap;  
  
  
    private boolean isConnectionTransactional;  
  
    private boolean autoCommit;  
  
  
    public MultiDataSourceTransaction(DataSource dataSource) {  
        this.dataSource = dataSource;  
        otherConnectionMap = new ConcurrentHashMap<>();  
    }  
  
    
	@Override
	public Connection getConnection() throws SQLException {
		String databaseIdentification = DynamicDataSourceContextHolder.getDataSourceType();
        if (databaseIdentification == null) {
            if (mainConnection != null) {
            	return mainConnection;
            }
            else {  
                openMainConnection();  
                return mainConnection;  
            }  
        } else {
            if (!otherConnectionMap.containsKey(databaseIdentification)) {
                try {  
                    Connection conn = dataSource.getConnection();  
                    otherConnectionMap.put(databaseIdentification, conn);  
                } catch (SQLException ex) {  
                    throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);
                }  
            }  
            return otherConnectionMap.get(databaseIdentification); 
        }
	}
        
    private void openMainConnection() throws SQLException {  
        this.mainConnection = DataSourceUtils.getConnection(this.dataSource);
        this.autoCommit = this.mainConnection.getAutoCommit();  
        this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.mainConnection, this.dataSource);
  
        if (LOGGER.isDebugEnabled()) {  
            LOGGER.debug(  
                    "JDBC Connection ["  
                            + this.mainConnection  
                            + "] will"  
                            + (this.isConnectionTransactional ? " " : " not ")  
                            + "be managed by Spring");  
        }  
    }  
    
    
	@Override
	public void commit() throws SQLException {
		if (this.mainConnection != null && !this.isConnectionTransactional && !this.autoCommit) {
            if (LOGGER.isDebugEnabled()) {  
                LOGGER.debug("Committing JDBC Connection [" + this.mainConnection + "]");  
            }  
            this.mainConnection.commit();  
            for (Connection connection : otherConnectionMap.values()) {  
                connection.commit();  
            }  
        }  

	}

	@Override
	public void rollback() throws SQLException {
		if (this.mainConnection != null && !this.isConnectionTransactional && !this.autoCommit) {  
            if (LOGGER.isDebugEnabled()) {  
                LOGGER.debug("Rolling back JDBC Connection [" + this.mainConnection + "]");  
            }  
            this.mainConnection.rollback();  
            for (Connection connection : otherConnectionMap.values()) {  
                connection.rollback();  
            }  
        }  
	}

	@Override
	public void close() throws SQLException {
		
		 DataSourceUtils.releaseConnection(this.mainConnection, this.dataSource);
	        for (Connection connection : otherConnectionMap.values()) {  
	            DataSourceUtils.releaseConnection(connection, this.dataSource);
	        }  

	}

	@Override
	public Integer getTimeout() throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

}

package com.hzy.work.database;

import org.apache.ibatis.session.TransactionIsolationLevel;
import org.apache.ibatis.transaction.Transaction;
import org.mybatis.spring.transaction.SpringManagedTransactionFactory;

import javax.sql.DataSource;

public class MultiDataSourceTransactionFactory extends SpringManagedTransactionFactory {
    @Override  
    public Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit) {
        return new MultiDataSourceTransaction(dataSource);  
    }  
} 
package com.hzy.work.database;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.mybatis.spring.boot.autoconfigure.MybatisProperties;
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
import org.mybatis.spring.mapper.ClassPathMapperScanner;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.util.List;


@org.springframework.context.annotation.Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnBean(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MybatisAutoConfiguration {

  private static final Logger logger = LoggerFactory.getLogger(MybatisAutoConfiguration.class);

  private final MybatisProperties properties;

  private final Interceptor[] interceptors;

  private final ResourceLoader resourceLoader;

  private final DatabaseIdProvider databaseIdProvider;

  private final List<ConfigurationCustomizer> configurationCustomizers;

  public MybatisAutoConfiguration(MybatisProperties properties,
                                  ObjectProvider<Interceptor[]> interceptorsProvider,
                                  ResourceLoader resourceLoader,
                                  ObjectProvider<DatabaseIdProvider> databaseIdProvider,
                                  ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider) {
    this.properties = properties;
    this.interceptors = interceptorsProvider.getIfAvailable();
    this.resourceLoader = resourceLoader;
    this.databaseIdProvider = databaseIdProvider.getIfAvailable();
    this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable();
  }

  @PostConstruct
  public void checkConfigFileExists() {
    if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) {
      Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation());
      Assert.state(resource.exists(), "Cannot find config location: " + resource
          + " (please add config file or check your Mybatis configuration)");
    }
  }

  @Bean
  @ConditionalOnMissingBean
  public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
    SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
    factory.setDataSource(dataSource);
    factory.setVfs(SpringBootVFS.class);
    if (StringUtils.hasText(this.properties.getConfigLocation())) {
      factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
    }
    Configuration configuration = this.properties.getConfiguration();
    if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {
      configuration = new Configuration();
    }
    if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
      for (ConfigurationCustomizer customizer : this.configurationCustomizers) {
        customizer.customize(configuration);
      }
    }
    factory.setConfiguration(configuration);
    if (this.properties.getConfigurationProperties() != null) {
      factory.setConfigurationProperties(this.properties.getConfigurationProperties());
    }
    if (!ObjectUtils.isEmpty(this.interceptors)) {
      factory.setPlugins(this.interceptors);
    }
    if (this.databaseIdProvider != null) {
      factory.setDatabaseIdProvider(this.databaseIdProvider);
    }
    if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
      factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
    }
    if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
      factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
    }
    if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
      factory.setMapperLocations(this.properties.resolveMapperLocations());
    }
    //事物工厂
    factory.setTransactionFactory(new MultiDataSourceTransactionFactory()); 
    
    return factory.getObject();
  }

  @Bean
  @ConditionalOnMissingBean
  public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
    ExecutorType executorType = this.properties.getExecutorType();
    if (executorType != null) {
      return new SqlSessionTemplate(sqlSessionFactory, executorType);
    } else {
      return new SqlSessionTemplate(sqlSessionFactory);
    }
  }

  /**
   * This will just scan the same base package as Spring Boot does. If you want
   * more power, you can explicitly use
   * {@link org.mybatis.spring.annotation.MapperScan} but this will get typed
   * mappers working correctly, out-of-the-box, similar to using Spring Data JPA
   * repositories.
   */
  public static class AutoConfiguredMapperScannerRegistrar
      implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware {

    private BeanFactory beanFactory;

    private ResourceLoader resourceLoader;

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

      logger.debug("Searching for mappers annotated with @Mapper");

      ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);

      try {
        if (this.resourceLoader != null) {
          scanner.setResourceLoader(this.resourceLoader);
        }

        List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
        if (logger.isDebugEnabled()) {
          for (String pkg : packages) {
            logger.debug("Using auto-configuration base package '{}'", pkg);
          }
        }

        scanner.setAnnotationClass(Mapper.class);
        scanner.registerFilters();
        scanner.doScan(StringUtils.toStringArray(packages));
      } catch (IllegalStateException ex) {
        logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.", ex);
      }
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
      this.beanFactory = beanFactory;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
      this.resourceLoader = resourceLoader;
    }
  }

  /**
   * {@link org.mybatis.spring.annotation.MapperScan} ultimately ends up
   * creating instances of {@link MapperFactoryBean}. If
   * {@link org.mybatis.spring.annotation.MapperScan} is used then this
   * auto-configuration is not needed. If it is _not_ used, however, then this
   * will bring in a bean registrar and automatically register components based
   * on the same component-scanning path as Spring Boot itself.
   */
  @org.springframework.context.annotation.Configuration
  @Import({ AutoConfiguredMapperScannerRegistrar.class })
  @ConditionalOnMissingBean(MapperFactoryBean.class)
  public static class MapperScannerRegistrarNotFoundConfiguration {

    @PostConstruct
    public void afterPropertiesSet() {
      logger.debug("No {} found.", MapperFactoryBean.class.getName());
    }
  }

}


package com.hzy.work.database;

import java.lang.annotation.*;

/**
* @Title TargetDataSource
* @author dailq 
* @create  2017年12月18日
*/

@Target({ ElementType.METHOD, ElementType.TYPE ,ElementType.LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
	String value();
}


3.yml配置你的数据库,需要多少个配置多少个(我这里只配了两个,默认情况下是default)

spring:
  datasource:
    druid:
      ds:
        #主数据库mysql
        default:
          url: jdbc:mysql://localhost:3306/learn?serverTimezone=GMT-8
          username: root
          password: root
          driverClassName: com.mysql.jdbc.Driver
        # cdh环境得impala
        cdh:
          url: jdbc:impala://127.0.0.1:21050/defaul
          username: root
          password: qwer@123
          driverClassName: com.cloudera.impala.jdbc41.Driver

4.如果我需要切换别的数据源就在service加如下注解
加了cdh注解就是用yml里cdh得数据源,没加就是default

	@TargetDataSource("cdh")
    public List<Map<String, Object>> testHive(String sql) {
        return userMapper.testHive(sql);
    }

    public List<Map<String, Object>> testMysql(String sql) {
        return userMapper.testHive(sql);
    }
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值