- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
但是在实际业务场景中,数据量迅速增长,一个库一个表已经满足不了我们的需求的时候,我们就会考虑分库分表的操作,在springboot中如何实现多数据源,动态数据源切换,读写分离等操作。 当你看到这篇文件那么你幸运了,下面直接提供终极通用版代码
如果是非Mybaitis的那么可以进行参照,原理都差不多
spring:
datasource:
default-db-key: voidme
multi-db:
- voidme:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
url: jdbc:mysql://192.168.42.153:3306/voidme?characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false&maxReconnects=10&useSSL=false
- xcdef:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
url: jdbc:mysql://192.168.42.153:3306/xcdef?characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false&maxReconnects=10&useSSL=false
mybatis:
#1.classpath:只会到你的classes路径中查找找文件。
#2.classpath*:不仅会到classes路径,还包括jar文件中(classes路径)进行查找。
mapper-locations: classpath*:/mapper/**/*Mapper.xml # mapper映射文件位置
type-aliases-package: com.**.entity # 实体类所在的位置
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #用于控制台打印sql语句
map-underscore-to-camel-case: true #开启将带有下划线的表字段 映射为驼峰格式的实体类属性
这个类用于获取数据源的(核心)
package com.dynamicdatadource.dynamic;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Value("${spring.datasource.default-db-key}")
private String defaultDbKey;
@Override
protected Object determineCurrentLookupKey() {
String currentDb = DynamicDataSourceService.currentDb();
if (currentDb == null) {
return defaultDbKey;
}
return currentDb;
}
}
这个类是数据源切换工具,我们做了线程隔离了所以不用担心多线程数据源会混乱的问题
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();
}
}
将数据源配置到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")
@Data
public 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());
}
}
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();
}
}
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
@Component
public 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;
}
// 还可以扩展包路径切换
}
运行程序之后,就会将数据源加入到数据源列表中了
从数据库中将配置信息查询出来,然后动态添加到数据源列表中
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;
*
* 上表要放入到默认数据源中的数据库里才行
*/
@Component
public 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实体类
@Data
public 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-Admin 服务监控 简单介绍 Spring Boot Actuator 是 Spring Boot 自带的一个功能模块, 提供了一组已经开箱即用的生产环境下常用
我想查找通过关键字匹配字段 nameEnglish 或 nameChinese 的模型列表。我花了一个多小时谷歌搜索但我做不到。请帮忙。 Springboot Mongo 入门示例 https://s
(请注意:在调查 this issue 时,我更好地发现了我在此处介绍的问题根源) 我对 Hibernate 和 SpringBoot 非常陌生。我的项目涉及一个搜索引擎,其中索引(javafx 客户
我最近有一个 Web 应用程序从 springboot 升级到 springboot 2。当我将其部署到 Tomcat 8 时,它似乎启动了,但没有完全启动。 在 localhost.2019-09-
我是 Spring boot 的新手...我在运行 Controller 时遇到问题, Description: Field todoService in com.springboot.todoCon
我有一个SpringBoot应用程序,它使用以下配置与PostgreSQL通信,通过AWS Beanstrik部署:。在我将AWS Aurora证书更新为rds-ca-ecc384-g1之前,一切都很
雪花算法的唯一性,在单个节点中是可以保证的,对应kubernetes中的应用,如果是横向扩展后,进行多副本的情况下,可能出现重复的ID,这需要我们按着pod_name进行一个workId的生成,我还是
实在是不知道标题写什么了 可以在评论区给个建议哈哈哈哈 先用这个作为标题吧 尝试使用 国内给出的 AI 大模型做出一个 可以和 AI 对话的 网站出来 使用 智普AI 只能 在控制
一、介绍 在实际的软件系统开发过程中,由于业务的需求,在代码层面实现数据的脱敏还是远远不够的,往往还需要在数据库层面针对某些关键性的敏感信息,例如:身份证号、银行卡号、手机号、工资等信息进行加密存储
Selenium Selenium是一个用于Web应用程序自动化测试的开源工具套件。它主要用于以下目的: 浏览器自动化:Selenium能够模拟真实用户在不同浏览器(如Chrome、Fire
一、简介 在实际的项目开发过程中,经常需要用到邮件通知功能。例如,通过邮箱注册,邮箱找回密码,邮箱推送报表等等,实际的应用场景非常的多。 早期的时候,为了能实现邮件的自动发送功能,通常会使用 Ja
SpringBoot:基于redis自定义注解实现后端接口防重复提交校验 一、添加依赖 org.springframework.boot spring
SpringBoot:使用Jackson完成全局序列化配置 一、测试准备 com.fasterxml.jackson.core jackson-cor
springboot:整合rocketmq 一、简易消息操作 生产者整合mq 导入依赖 org.springframework.boot
springboot:常用注解 一、spring常用注解 包扫描+组件标注注解 @Component:泛指各种组件 @Controller、@Service、@Repository都可以称为@Comp
我们经常需要在两个系统之间进行一些数据的交互,这时候我们就需要开发数据交互接口。 一般来说,遇到比较多的接口有HTTP接口、WebService接口、FTP文件传输。今天我要来学习一下在SpringB
背景 近期项目上线,甲方要求通过安全检测才能进行验收,故针对扫描结果对系统进行了一系列的安全加固,本文对一些常见的安全问题及防护策略进行介绍,提供对应的解决方案 跨站脚本攻击 XSS常发生于论坛评论等
1.排除 Spring-boot-starter 默认的日志配置 将原本的 spring-boot-starter 改为 org.springframework.boot
springboot:解决跨域问题 一、跨域简介 URL的组成: // 协议 + 域名(子域名 + 主域名) + 端口号 + 资源地址 http://www.baidu.com:8080/ 只要协
一、自定义Starter 的思路: 创建一个Maven工程,创建三个模块 一个模块为demo-app,一个模块为demo-module,一个模块为demo-module-springboot-star
我是一名优秀的程序员,十分优秀!