springboot自动切换数据源,springboot2.0实现多数据源

  springboot自动切换数据源,springboot2.0实现多数据源

  

目录

前言配置文件(YML)核心代码动态数据资源动态数据资源服务动态数据资源配置加载YML数据库配置类面向切面编程(面向方面的编程的缩写)切换效果扩展MysqlDataSourceInitializeDataSourceEneity实体类总结

 

  

前言

但是在实际业务场景中,数据量迅速增长,一个库一个表已经满足不了我们的需求的时候,我们就会考虑分库分表的操作,在跳羚中如何实现多数据源,动态数据源切换,读写分离等操作。当你看到这篇文件那么你幸运了,下面直接提供终极通用版代码

 

  如果是非Mybaitis的那么可以进行参照,原理都差不多

  

配置文件(YML)

spring :数据源: default-d b-key : void me multi-db :-void me : driver-class-name : com。MySQL。CJ。JDBC。驱动用户名: root密码: root URL : JDBC : MySQL 3://192。168 .42 .162 .162 character encoding=utf 8 autore connect=truefailOverReadOnly=false maxreconnects=10 use SSL=false-xcdef : driver-class-name : com。MySQL。CJ。JDBC。驾驶员用户名:根密码:根网址: JDBC : MySQL 3360//192。168 .42 .1533:3306/xc def?字符编码=ut F8 autore connect=truefailOverReadOnly=false maxreconnects=10使用SSL=false mybatis 3360 # 1。类别路径:只会到你的班路径中查找找文件。类路径*:不仅会到班路径,还包括冲突文件中(类别路径)进行查找映射器-位置:类路径* :/映射器/* */*映射器。XML #映射器映射文件位置类型-别名-包装: com .**.实体#实体类所在的位置配置:日志-impl :组织。阿帕奇。伊巴提斯。伐木。stdout。标准输出实现#用于控制台打印结构化查询语言语句地图-下划线-驼色:真#开启将带有下划线的表字段映射为驼峰格式的实体类属性

 

  

核心代码

 

  

DynamicDataSource

这个类用于获取数据源的(核心)

 

  包com。动态数据。动态;导入org。spring框架。豆子。工厂。注释。价值;导入组织。spring框架。JDBC。数据来源。查找。abstractroutingdatasource公共类动态数据源扩展AbstractRoutingDataSource { @ Value($ { spring。数据来源。default-d b-key } )私有字符串defaultDbKey@ Override保护对象determineCurrentLookupKey(){ String currentDb=dynamicdatasourceservice。current db();if(current db==null){ return defaultDbKey;}返回当前值Db}}

  

DynamicDataSourceService

这个类是数据源切换工具,我们做了线程隔离了所以不用担心多线程数据

 

  源会混乱的问题

  

package com.dynamicdatadource.dynamic;import com.application.ApplicationContextProvider;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.boot.jdbc.DataSourceBuilder;import javax.sql.DataSource;import java.util.HashMap;import java.util.Map;public class DynamicDataSourceService { private static final Logger log = LoggerFactory.getLogger(DynamicDataSourceService.class); private static final Map<Object, Object> dataSources = new HashMap<>(); private static final ThreadLocal<String> dbKeys = ThreadLocal.withInitial(() -> null); /** * 动态添加一个数据源 * * @param name 数据源的key * @param dataSource 数据源对象 */ public static void addDataSource(String name, DataSource dataSource) { DynamicDataSource dynamicDataSource = ApplicationContextProvider.getApplicationContext().getBean(DynamicDataSource.class); dataSources.put(name, dataSource); dynamicDataSource.setTargetDataSources(dataSources); dynamicDataSource.afterPropertiesSet(); log.info("添加了数据源:{}",name); } /** * @param name 数据源的key * @param driverClassName 驱动 * @param url 数据库连接地址 * @param username 数据库账户 * @param password 数据库密码 */ public static void addDataSource(String name, String driverClassName,String url,String username,String password) { DataSourceBuilder<?> builder = DataSourceBuilder.create(); builder.driverClassName(driverClassName); builder.username(username); builder.password(password); builder.url(url); addDataSource(name,builder.build()); log.info("添加了数据源:{}",name); } /** * 切换数据源 */ public static void switchDb(String dbKey) { dbKeys.set(dbKey); } /** * 重置数据源(切换为默认的数据源) */ public static void resetDb() { dbKeys.remove(); } /** * 获取当前数据源的key */ public static String currentDb() { return dbKeys.get(); }}

 

  

DynamicDataSourceConfig

将数据源配置到springboot中和初始化Mybaitis配置

 

  

package com.dynamicdatadource.dynamic;import lombok.Data;import org.apache.ibatis.logging.Log;import org.mybatis.spring.SqlSessionFactoryBean;import org.springframework.boot.context.properties.ConfigurationProperties;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 org.springframework.transaction.PlatformTransactionManager;import java.io.IOException;import java.util.HashMap;import java.util.Map;@Configuration@ConfigurationProperties(prefix = "mybatis")@Datapublic class DynamicDataSourceConfig { private String mapperLocations; private String typeAliasesPackage; @Data public class MybatisConfiguration{ private String logImpl; private boolean mapUnderscoreToCamelCase; } private MybatisConfiguration configuration=new MybatisConfiguration(); /** * 动态数据源 */ @Bean public DynamicDataSource dynamicDataSource() { DynamicDataSource dataSource = new DynamicDataSource(); Map<Object, Object> targetDataSources = new HashMap<>(); dataSource.setTargetDataSources(targetDataSources); return dataSource; } /** * 会话工厂Mybaitis */ @Bean public SqlSessionFactoryBean sqlSessionFactoryBean() throws IOException, ClassNotFoundException { org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration(); configuration.setMapUnderscoreToCamelCase(this.configuration.isMapUnderscoreToCamelCase()); //开启驼峰命名 configuration.setLogImpl((Class<? extends Log>) Class.forName(this.configuration.getLogImpl())); //控制台打印sql日志 SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dynamicDataSource()); sqlSessionFactoryBean.setConfiguration(configuration); PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); sqlSessionFactoryBean.setMapperLocations(resolver.getResources(mapperLocations)); sqlSessionFactoryBean.setTypeAliasesPackage(typeAliasesPackage); return sqlSessionFactoryBean; } /** * 事务管理器 */ @Bean public PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(dynamicDataSource()); }}

 

  

加载YML数据库配置类

package com.dynamicdatadource.config;import com.dynamicdatadource.dynamic.DynamicDataSourceService;import lombok.Data;import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.boot.jdbc.DataSourceBuilder;import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;import javax.sql.DataSource;import java.util.List;import java.util.Map;import java.util.Set;@Component@Data@ConfigurationProperties(prefix = "spring.datasource")public class YmlDataSourceProvider { private List<Map<String, DataSourceProperties>> multiDb; private DataSource buildDataSource(DataSourceProperties prop) { DataSourceBuilder<?> builder = DataSourceBuilder.create(); builder.driverClassName(prop.getDriverClassName()); builder.username(prop.getUsername()); builder.password(prop.getPassword()); builder.url(prop.getUrl()); return builder.build(); } public void initDataSource() { multiDb.forEach(map -> { Set<String> keys = map.keySet(); keys.forEach(key -> { DataSourceProperties properties = map.get(key); DataSource dataSource = buildDataSource(properties); DynamicDataSourceService.addDataSource(key, dataSource); }); }); } //在构造函数之后执行 @PostConstruct public void init() { initDataSource(); }}

 

  

aop切换

package com.dynamicdatadource.aop;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)public @interface DynamicDataSourceAnno { String key() default "";}
package com.dynamicdatadource.aop;import com.dynamicdatadource.dynamic.DynamicDataSourceService;import org.apache.commons.lang.StringUtils;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.aspectj.lang.reflect.MethodSignature;import org.springframework.stereotype.Component;// 用于单独的请求或者类进行切换数据库@Aspect@Componentpublic class DynamicDataSourceAspect { @Pointcut("@annotation(com.dynamicdatadource.aop.DynamicDataSourceAnno)") public void dynamicDataSourceAnno() { } @Around("dynamicDataSourceAnno()") public Object DynamicDataSourceAspectAroundAnno(ProceedingJoinPoint joinPoint) { Object object = null; try { MethodSignature signature = (MethodSignature)joinPoint.getSignature(); DynamicDataSourceAnno dynamicDataSourceAnno = signature.getMethod().getAnnotation(DynamicDataSourceAnno.class); String key = dynamicDataSourceAnno.key(); if (StringUtils.isNotBlank(key)) { //切换为指定数据库 DynamicDataSourceService.switchDb(key); } object = joinPoint.proceed(); } catch (Throwable e) { e.printStackTrace(); }finally { //还原为默认配置 DynamicDataSourceService.resetDb(); } return object; } // 还可以扩展包路径切换}

 

  

效果

运行程序之后,就会将数据源加入到数据源列表中了

 

  

 

  

 

  

扩展

 

  

MysqlDataSourceInitialize

从数据库中将配置信息查询出来,然后动态添加到数据源列表中

 

  

package com.dao.config;import com.dao.DatasourceDao;import com.dynamicdatadource.aop.DynamicDataSourceAnno;import com.dynamicdatadource.dynamic.DynamicDataSourceService;import com.entity.DataSourceEneity;import org.springframework.beans.factory.InitializingBean;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.ApplicationArguments;import org.springframework.boot.ApplicationRunner;import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;import javax.sql.DataSource;import java.util.List;//从数据库中查询出全部的数据源,添加到数据源容器中/** * 表结构如下: * * CREATE TABLE `t_datasource` ( * `id` int(11) NOT NULL, * `key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 绑定的key,用于数据源的切换, * `url` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 数据库连接地址, * `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 数据库用户名, * `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 数据库密码, * `driverClassName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 数据库驱动, * `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 数据库类型: mysql ,oracle,.., * `state` int(2) NOT NULL COMMENT 是否可用: 1可用 ,2不可用, * PRIMARY KEY (`id`), * UNIQUE KEY `key` (`key`) * ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; * * 上表要放入到默认数据源中的数据库里才行 */@Componentpublic class MysqlDataSourceInitialize implements ApplicationRunner { @Autowired private DatasourceDao datasourceDao; //项目启动后执行初始化数据源 @Override public void run(ApplicationArguments args) throws Exception { try { List<DataSourceEneity> dataSources = datasourceDao.getDataSources(); for (DataSourceEneity dataSource : dataSources) { DynamicDataSourceService.addDataSource(dataSource.getKey(),dataSource.getDataSource()); } } catch (Exception e) { e.printStackTrace(); } }}

 

  

DataSourceEneity实体类

@Datapublic class DataSourceEneity { private int id; private String key; private String url; private String username; private String password; private String driverClassName; private String type; private int state; public DataSource getDataSource() { DataSourceBuilder<?> builder = DataSourceBuilder.create(); builder.driverClassName(driverClassName); builder.username(username); builder.password(password); builder.url(url); return builder.build(); }}

 

  

总结

到此这篇关于SpringBoot多数据源切换实现的文章就介绍到这了,更多相关SpringBoot多数据源切换内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

 

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: