springboot2多数据源配置,springboot2.0实现多数据源
目录
第一种方式:方法二在我们的实际业务中可能会遇到;在一个项目里面读取多个数据库的数据来进行展示,春天对同时配置多个数据源是支持的。
本文中将展示两种方法来实现这个功能。
跳趾蝠
第一种方式:
在配置文件中配置多个数据源,然后通过配置类来获取数据源以及制图人相关的扫描配置
pom.xml
parentgroupidorg。spring框架。boot/groupid artifactid spring-boot-starter-parent/artifactid version 1。5 .9 .版本/版本相关路径//父级依赖项!德鲁伊数据源驱动-依赖groupIdcom.alibaba/groupId artifactId德鲁伊-spring-boot-starter/artifactId版本1。1 .0/版本/依赖项依赖关系groupId MySQL/groupId artifact id MySQL-connector-Java/artifact id/dependency!-我的巴蒂斯跳羚依赖-dependencygroupidorg。spring框架。boot/groupid artifactId spring-boot-starter-web/artifactId/dependency依赖关系groupIdorg.springframework.boot/groupId artifactId spring-boot-starter-Tomcat/artifactId scope compile/scope/dependency依赖关系groupidorg。spring框架。boot/groupid artifact id spring-boot-starter-test/artifact id/dependency!- aop依赖-dependency groupIdorg.springframework.boot/groupId artifact id spring-boot-starter-AOP/artifact id/dependency!-我的巴蒂斯-依赖groupIdorg.mybatis.spring.boot/groupId artifactId我的巴蒂斯-弹簧-启动-启动/artifactId版本1 . 3 . 1/版本/依赖关系!-通用映射器-依赖关系groupIdtk.mybatis/groupId工艺品Id映射器-弹簧靴启动器/artifactId版本1 . 1 . 5/版本/依赖关系!德鲁伊监控依赖-dependencygroupid com。阿里巴巴/groupid artifactiddruid/artifactid版本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")@Configurationpublic 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)@Documentedpublic @interface TargetDataSource {String value();}
DynamicDataSource
package com.sysmg.common.config.datasoure; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class DynamicDataSource extends AbstractRoutingDataSource { @Overrideprotected 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之前执行@Componentpublic 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>(); @Overridepublic 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);// falsedataBinder.setIgnoreInvalidFields(false);// falsedataBinder.setIgnoreUnknownFields(true);// trueif (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);} @Overridepublic 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:///article/239952.htm,这里的mapper文件和实体扫描可以跟默认的数据源配置相同即可
到此这篇关于springboot配置多个数据源两种方式实现的文章就介绍到这了,更多相关springboot配置多个数据源内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。