springboot配置多个数据源两种方式实现

网友投稿 396 2022-08-22


springboot配置多个数据源两种方式实现

目录第一种方式:方法二

在我们的实际业务中可能会遇到;在一个项目里面读取多个数据库的数据来进行展示,spring对同时配置多个数据源是支持的。

本文中将展示两种方法来实现这个功能。

springboot+mybatis

第一种方式:

在配置文件中配置多个数据源,然后通过配置类来获取数据源以及mapper相关的扫描配置

pom.xml

org.springframework.boot

spring-boot-starter-parent

1.5.9.RELEASE

com.alibaba

druid-spring-boot-starter

1.1.0

mysql

mysql-connector-java

org.springframework.boot

spring-boot-starter-web

org.springframework.boot

spring-boot-starter-tomcat

compile

org.springframework.boot

spring-boot-starter-test

org.springframework.boot

spring-boot-starter-aop

org.mybatis.spring.boot

mybatis-spring-boot-starter

1.3.1

tk.mybatis

mapper-spring-boot-starter

1.1.5

com.alibaba

druid

1.0.28

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之前KXgMrswL执行

@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.setDatKXgMrswLaSourceType(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 contextHolder = new ThreadLocal();

public static List dataSourceIds = new ArrayList();

public static void setDataSourceType(String dataSourceType) {

contextHolder.set(dataSourceType);

}

public KXgMrswLstatic 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 customDataSources = new HashMap();

@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 dsMap = new HashMap();

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 dsMap = propertyResolver.getSubProperties(dsPrefix + ".");

DataSource ds = buildDataSource(dsMap);

customDataSources.put(dsPrefix, ds);

dataBinder(ds, env);

}

}

@SuppressWarnings("unchecked")

public DataSource buildDataSource(Map 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 rpr = new RelaxedPropertyResolver(env, "spring.datasource").getSubProperties(".");

Map 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 targetDataSources = new HashMap();

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://jb51.net/article/239952.htm,这里的mapper文件和实体扫描可以跟默认的数据源配置相同即可


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Python之文件操作(python文件基本操作)
下一篇:Linux之安装本地Python和pip
相关文章

 发表评论

暂时没有评论,来抢沙发吧~