在我们的实际业务中可能会遇到;在一个项目里面读取多个数据库的数据来进行展示,spring对同时配置多个数据源是支持的。
本文中将展示两种方法来实现这个功能。
springboot+mybatis
第一种方式:
在配置文件中配置多个数据源,然后通过配置类来获取数据源以及mapper相关的扫描配置
pom.xml
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>1.5.9.RELEASE</version>
- <relativePath/>
- </parent>
- <dependencies>
- <!-- druid数据源驱动 -->
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid-spring-boot-starter</artifactId>
- <version>1.1.0</version>
- </dependency>
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- </dependency>
- <!--mybatis SpringBoot依赖 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-tomcat</artifactId>
- <scope>compile</scope>
- </dependency>
-
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- </dependency>
-
- <!-- aop依赖 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-aop</artifactId>
- </dependency>
-
- <!-- mybatis -->
- <dependency>
- <groupId>org.mybatis.spring.boot</groupId>
- <artifactId>mybatis-spring-boot-starter</artifactId>
- <version>1.3.1</version>
- </dependency>
-
- <!-- 通用mapper -->
- <dependency>
- <groupId>tk.mybatis</groupId>
- <artifactId>mapper-spring-boot-starter</artifactId>
- <version>1.1.5</version>
- </dependency>
- <!-- druid监控依赖 -->
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid</artifactId>
- <version>1.0.28</version>
- </dependency>
- </dependencies>
application.yml
- spring:
- datasource:
- type: com.alibaba.druid.pool.DruidDataSource
- driverClassName: com.mysql.jdbc.Driver
-
- url: jdbc:mysql://127.0.0.1:3306/test2?useUnicode=true&characterEncoding=utf8
- username: root
- password: 123456
-
- url2: jdbc:mysql://127.0.0.1:3306/test1?useUnicode=true&characterEncoding=utf8
- username2: root
- password2: 123456
DruidDBConfig 连接池相关配置
- package com.xbz.common.config;
-
- import com.alibaba.druid.support.http.StatViewServlet;
- import com.alibaba.druid.support.http.WebStatFilter;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.boot.web.servlet.FilterRegistrationBean;
- import org.springframework.boot.web.servlet.ServletRegistrationBean;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
-
- /**
- * Druid监控
- */
- @SuppressWarnings("AlibabaRemoveCommentedCode")
- @Configuration
- public class DruidDBConfig {
- private Logger logger = LoggerFactory.getLogger(DruidDBConfig.class);
-
- /**
- * 注册ServletRegistrationBean
- * @return
- */
- @Bean
- public ServletRegistrationBean druidServlet() {
- ServletRegistrationBean reg = new ServletRegistrationBean();
- reg.setServlet(new StatViewServlet());
- reg.addUrlMappings("/druid/*");
- reg.addInitParameter("allow", ""); //白名单
- return reg;
- }
-
- /**
- * 注册FilterRegistrationBean
- * @return
- */
- @Bean
- public FilterRegistrationBean filterRegistrationBean() {
- FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
- filterRegistrationBean.setFilter(new WebStatFilter());
- filterRegistrationBean.addUrlPatterns("/*");
- filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
- filterRegistrationBean.addInitParameter("profileEnable", "true");
- filterRegistrationBean.addInitParameter("principalCookieName", "USER_COOKIE");
- filterRegistrationBean.addInitParameter("principalSessionName", "USER_SESSION");
- filterRegistrationBean.addInitParameter("DruidWebStatFilter", "/*");
- return filterRegistrationBean;
- }
- }
MasterDbConfig 注意读取数据库连接相关的键,以及扫描实体、mapper等
- package com.xbz.common.config;
-
- import com.alibaba.druid.pool.DruidDataSource;
- import org.apache.ibatis.session.SqlSessionFactory;
- import org.mybatis.spring.SqlSessionFactoryBean;
- import org.mybatis.spring.annotation.MapperScan;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.beans.factory.annotation.Qualifier;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.context.annotation.Primary;
- import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
- import org.springframework.jdbc.datasource.DataSourceTransactionManager;
-
- import javax.sql.DataSource;
- import java.sql.SQLException;
-
-
- @Configuration
- @MapperScan(basePackages = MasterDbConfig.PACKAGE , sqlSessionFactoryRef = "masterSqlSessionFactory")
- public class MasterDbConfig {
- private Logger logger = LoggerFactory.getLogger(MasterDbConfig.class);
- // 精确到 master 目录,以便跟其他数据源隔离
- static final String PACKAGE = "com.xbz.**.dao.master";
- private static final String MAPPER_LOCATION = "classpath*:mapper/master/*.xml";
- private static final String DOMAIN_PACKAGE = "com.xbz.**.domain";
-
- @Value("${spring.datasource.url}")
- private String dbUrl;
-
- @Value("${spring.datasource.username}")
- private String username;
-
- @Value("${spring.datasource.password}")
- private String password;
-
- @Value("${spring.datasource.driverClassName}")
- private String driverClassName;
-
-
- @Bean(name="masterDataSource") //声明其为Bean实例
- @Primary //在同样的DataSource中,首先使用被标注的DataSource
- public DataSource masterDataSource() {
- DruidDataSource datasource = new DruidDataSource();
-
- datasource.setUrl(this.dbUrl);
- datasource.setUsername(username);
- datasource.setPassword(password);
- datasource.setDriverClassName(driverClassName);
-
- return datasource;
- }
-
- @Bean(name = "masterTransactionManager")
- @Primary
- public DataSourceTransactionManager masterTransactionManager() {
- return new DataSourceTransactionManager(masterDataSource());
- }
-
- @Bean(name = "masterSqlSessionFactory")
- @Primary
- public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource masterDataSource)
- throws Exception {
- final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
- sessionFactory.setDataSource(masterDataSource);
- sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
- .getResources(MasterDbConfig.MAPPER_LOCATION));
- sessionFactory.setTypeAliasesPackage(DOMAIN_PACKAGE);
- //mybatis 数据库字段与实体类属性驼峰映射配置
- sessionFactory.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
- return sessionFactory.getObject();
- }
- }
ClusterDbConfig
- package com.xbz.common.config;
-
- import com.alibaba.druid.pool.DruidDataSource;
- import org.apache.ibatis.session.SqlSessionFactory;
- import org.mybatis.spring.SqlSessionFactoryBean;
- import org.mybatis.spring.annotation.MapperScan;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.beans.factory.annotation.Qualifier;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
- import org.springframework.jdbc.datasource.DataSourceTransactionManager;
-
- import javax.sql.DataSource;
- import java.sql.SQLException;
-
- /**
- * 从数据源配置
- * 若需要配置更多数据源 , 直接在yml中添加数据源配置再增加相应的新的数据源配置类即可
- */
- @Configuration
- @MapperScan(basePackages = ClusterDbConfig.PACKAGE , sqlSessionFactoryRef = "clusterSqlSessionFactory")
- public class ClusterDbConfig {
- private Logger logger = LoggerFactory.getLogger(ClusterDbConfig.class);
- // 精确到 cluster 目录,以便跟其他数据源隔离
- static final String PACKAGE = "com.xbz.**.dao.cluster";
- private static final String MAPPER_LOCATION = "classpath*:mapper/cluster/*.xml";
- private static final String DOMAIN_PACKAGE = "com.xbz.**.domain";
-
- @Value("${spring.datasource.url2}")
- private String dbUrl;
-
- @Value("${spring.datasource.username2}")
- private String username;
-
- @Value("${spring.datasource.password2}")
- private String password;
-
- @Value("${spring.datasource.driverClassName}")
- private String driverClassName;
-
-
-
- @Bean(name="clusterDataSource") //声明其为Bean实例
- public DataSource clusterDataSource() {
- DruidDataSource datasource = new DruidDataSource();
-
- datasource.setUrl(this.dbUrl);
- datasource.setUsername(username);
- datasource.setPassword(password);
- datasource.setDriverClassName(driverClassName);
- return datasource;
- }
-
- @Bean(name = "clusterTransactionManager")
- public DataSourceTransactionManager clusterTransactionManager() {
- return new DataSourceTransactionManager(clusterDataSource());
- }
-
- @Bean(name = "clusterSqlSessionFactory")
- public SqlSessionFactory clusterSqlSessionFactory(@Qualifier("clusterDataSource") DataSource culsterDataSource)
- throws Exception {
- final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
- sessionFactory.setDataSource(culsterDataSource);
- sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
- .getResources(ClusterDbConfig.MAPPER_LOCATION));
- sessionFactory.setTypeAliasesPackage(DOMAIN_PACKAGE);
- //mybatis 数据库字段与实体类属性驼峰映射配置
- sessionFactory.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
- return sessionFactory.getObject();
- }
- }

不同的数据源配置不佟的mapper扫描位置,然后需要哪一个数据源就注入哪一个mapper接口即可


这样获取的数据就是来自不同的数据源了,这种方法比较简单。
方法二
配置一个默认使用的数据源,然后定义多个其他的数据源,使用aop形成注解式选择数据源
- # 默认数据源
-
- spring:
- datasource:
- druid:
- # 数据库访问配置, 使用druid数据源
- type: com.alibaba.druid.pool.DruidDataSource
- driverClassName: com.mysql.jdbc.Driver
- url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8
- username: root
- password: 123456
-
- # 其他数据源
-
- custom:
- datasource:
- druid:
- type: com.alibaba.druid.pool.DruidDataSource
- names: fishlog,fishgame
- fishlog:
- driverClassName: com.mysql.jdbc.Driver
- url: jdbc:mysql://127.0.0.1:3306/test1?useUnicode=true&characterEncoding=utf8
- username: root
- password: 123456
- fishgame:
- driverClassName: com.mysql.jdbc.Driver
- url: jdbc:mysql://127.0.0.1:3306/test2?useUnicode=true&characterEncoding=utf8
- username: root
- password: 123456
然后启动类中注入注解

注解类及参数value TargetDataSource
- package com.sysmg.common.config.datasoure;
-
- import java.lang.annotation.Documented;
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
-
- @Target({ ElementType.METHOD, ElementType.TYPE })
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface TargetDataSource {
- String value();
- }
DynamicDataSource
- package com.sysmg.common.config.datasoure;
-
- import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
-
- public class DynamicDataSource extends AbstractRoutingDataSource {
-
- @Override
- protected Object determineCurrentLookupKey() {
- return DynamicDataSourceContextHolder.getDataSourceType();
- }
-
- }
DynamicDataSourceAspect切面实现
- package com.sysmg.common.config.datasoure;
-
- 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.springframework.core.annotation.Order;
- import org.springframework.stereotype.Component;
-
- @Aspect
- @Order(-10) // 保证该AOP在@Transactional之前执行
- @Component
- public class DynamicDataSourceAspect {
- @Before("@annotation(targetDataSource)")
- public void changeDataSource(JoinPoint point, TargetDataSource targetDataSource) throws Throwable {
- String dsId = targetDataSource.value();
- if (!DynamicDataSourceContextHolder.containsDataSource(dsId)) {
- System.err.println("数据源[{}]不存在,使用默认数据源 > {}" + targetDataSource.value() + point.getSignature());
- } else {
- System.out.println("UseDataSource : {} > {}" + targetDataSource.value() + point.getSignature());
- DynamicDataSourceContextHolder.setDataSourceType(targetDataSource.value());
- }
- }
-
- @After("@annotation(targetDataSource)")
- public void restoreDataSource(JoinPoint point, TargetDataSource targetDataSource) {
- System.out.println("RevertDataSource : {} > {}"+targetDataSource.value()+point.getSignature());
- DynamicDataSourceContextHolder.clearDataSourceType();
- }
- }
DynamicDataSourceContextHolder
- package com.sysmg.common.config.datasoure;
-
- import java.util.ArrayList;
-
- import java.util.List;
-
- public class DynamicDataSourceContextHolder {
- private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
- public static List<String> dataSourceIds = new ArrayList<String>();
-
- public static void setDataSourceType(String dataSourceType) {
- contextHolder.set(dataSourceType);
- }
-
- public static String getDataSourceType() {
- return contextHolder.get();
- }
-
- public static void clearDataSourceType() {
- contextHolder.remove();
- }
-
- public static boolean containsDataSource(String dataSourceId){
- return dataSourceIds.contains(dataSourceId);
- }
- }
DynamicDataSourceRegister数据源注册类
- package com.sysmg.common.config.datasoure;
-
- import java.util.HashMap;
- import java.util.Map;
- import javax.sql.DataSource;
- import org.springframework.beans.MutablePropertyValues;
- import org.springframework.beans.PropertyValues;
- import org.springframework.beans.factory.support.BeanDefinitionRegistry;
- import org.springframework.beans.factory.support.GenericBeanDefinition;
- import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
- import org.springframework.boot.bind.RelaxedDataBinder;
- import org.springframework.boot.bind.RelaxedPropertyResolver;
- import org.springframework.context.EnvironmentAware;
- import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
- import org.springframework.core.convert.ConversionService;
- import org.springframework.core.convert.support.DefaultConversionService;
- import org.springframework.core.env.Environment;
- import org.springframework.core.type.AnnotationMetadata;
-
- public class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {
- private static final Object DATASOURCE_TYPE_DEFAULT = "com.alibaba.druid.pool.DruidDataSource";
- private ConversionService conversionService = new DefaultConversionService();
- private PropertyValues dataSourcePropertyValues;
- private DataSource defaultDataSource;
- private Map<String, DataSource> customDataSources = new HashMap<String, DataSource>();
-
- @Override
- public void setEnvironment(Environment environment) {
- System.out.println("DynamicDataSourceRegister.setEnvironment()");
- initDefaultDataSource(environment);
- initCustomDataSources(environment);
- }
-
- private void initDefaultDataSource(Environment env) {
- RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "spring.datasource.druid.");
- Map<String, Object> dsMap = new HashMap<String, Object>();
- dsMap.put("type", propertyResolver.getProperty("type"));
- dsMap.put("driverClassName", propertyResolver.getProperty("driverClassName"));
- dsMap.put("url", propertyResolver.getProperty("url"));
- dsMap.put("username", propertyResolver.getProperty("username"));
- dsMap.put("password", propertyResolver.getProperty("password"));
- defaultDataSource = buildDataSource(dsMap);
- dataBinder(defaultDataSource, env);
- }
-
- private void initCustomDataSources(Environment env) {
- RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "custom.datasource.druid.");
- String dsPrefixs = propertyResolver.getProperty("names");
- for (String dsPrefix : dsPrefixs.split(",")) {// 多个数据源
- Map<String, Object> dsMap = propertyResolver.getSubProperties(dsPrefix + ".");
- DataSource ds = buildDataSource(dsMap);
- customDataSources.put(dsPrefix, ds);
- dataBinder(ds, env);
- }
- }
-
- @SuppressWarnings("unchecked")
- public DataSource buildDataSource(Map<String, Object> dsMap) {
- Object type = dsMap.get("type");
- if (type == null) {
- type = DATASOURCE_TYPE_DEFAULT;// 默认DataSource
- }
- Class<? extends DataSource> dataSourceType;
- try {
- dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);
- String driverClassName = dsMap.get("driverClassName").toString();
- String url = dsMap.get("url").toString();
- String username = dsMap.get("username").toString();
- String password = dsMap.get("password").toString();
- DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url)
- .username(username).password(password).type(dataSourceType);
- return factory.build();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- return null;
- }
-
- private void dataBinder(DataSource dataSource, Environment env) {
- RelaxedDataBinder dataBinder = new RelaxedDataBinder(dataSource);
- dataBinder.setConversionService(conversionService);
- dataBinder.setIgnoreNestedProperties(false);// false
- dataBinder.setIgnoreInvalidFields(false);// false
- dataBinder.setIgnoreUnknownFields(true);// true
- if (dataSourcePropertyValues == null) {
- Map<String, Object> rpr = new RelaxedPropertyResolver(env, "spring.datasource").getSubProperties(".");
- Map<String, Object> values = new HashMap<>(rpr);
- values.remove("type");
- values.remove("driverClassName");
- values.remove("url");
- values.remove("username");
- values.remove("password");
- dataSourcePropertyValues = new MutablePropertyValues(values);
- }
- dataBinder.bind(dataSourcePropertyValues);
- }
-
- @Override
- public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
- System.out.println("DynamicDataSourceRegister.registerBeanDefinitions()");
- Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
- targetDataSources.put("dataSource", defaultDataSource);
- DynamicDataSourceContextHolder.dataSourceIds.add("dataSource");
- targetDataSources.putAll(customDataSources);
- for (String key : customDataSources.keySet()) {
- DynamicDataSourceContextHolder.dataSourceIds.add(key);
- }
- GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
- beanDefinition.setBeanClass(DynamicDataSource.class);
- beanDefinition.setSynthetic(true);
- MutablePropertyValues mpv = beanDefinition.getPropertyValues();
- mpv.addPropertyValue("defaultTargetDataSource", defaultDataSource);
- mpv.addPropertyValue("targetDataSources", targetDataSources);
- registry.registerBeanDefinition("dataSource", beanDefinition);
- }
- }

这里使用的时候把需要使用的表名注入,如果是默认的数据源,则不需要加这个注解,具体的springboot自定义注解的建立,可参考https://www.jb51.net/article/239952.htm,这里的mapper文件和实体扫描可以跟默认的数据源配置相同即可
到此这篇关于springboot配置多个数据源两种方式实现的文章就介绍到这了,更多相关springboot配置多个数据源内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!