java配置多数据源

三个数据库:master主库、back_one从库1、back_two从库2

1.application.yml配置三个数据库信息

spring:datasource:driver-class-name : com.mysql.jdbc.Driver# 主库master:jdbcUrl : jdbc:mysql://xxx:3306/master?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2b8&allowMultiQueries=trueusername : xxxpassword : xxxname :# 从库1slave:enabled: true  # 从数据源开关/默认关闭jdbcUrl: jdbc:mysql://xxx:3306/back_one?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=GMT%2b8username: xxxpassword: xxxname :# 从库2slave2:enabled: true  # 从数据源开关/默认关闭jdbcUrl: jdbc:mysql://xxx:3306/back_two?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=GMT%2b8username: xxxpassword: xxxname :druid.maxActive : 150druid.initialSize : 5druid.minIdle : 5druid.maxWait : 60000druid.filters : statdruid.timeBetweenEvictionRunsMillis : 60000druid.minEvictableIdleTimeMillis : 300000druid.validationQuery : SELECT 1    #多个数据源时配置:select count(*) from dualdruid.testWhileIdle : truedruid.testOnBorrow : falsedruid.testOnReturn : falsedruid.poolPreparedStatements : falsedruid.maxPoolPreparedStatementPerConnectionSize : -1druid.timeBetweenLogStatsMillis : 0druid.keep-alive : truedruid.connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000;druid.stat.logSlowSql=true

注意:

一个数据源时:validationQuery: SELECT 1;

多个数据源时:validationQuery: select count(*) from dual

2.代码

(1)DataSource

import java.lang.annotation.*;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {DataSourceType value() default DataSourceType.MASTER;}

(2)DataSourceAspect

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.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;@Aspect
@Order(1)
@Component
public class DataSourceAspect {@Pointcut("execution(public * com.xxx.mapper..*.*(..))")public void pointcut() {}@Before("pointcut()")public void doBefore(JoinPoint joinPoint){Method method = ((MethodSignature)joinPoint.getSignature()).getMethod();DataSource dataSource = method.getAnnotation(DataSource.class);  //获取方法上的注解if(dataSource == null){Class<?> clazz= joinPoint.getTarget().getClass().getInterfaces()[0];dataSource =clazz.getAnnotation(DataSource.class);  //获取类上面的注解if(dataSource == null) return;}if (dataSource != null) {DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());}}@After("pointcut()")public void after(JoinPoint point) {//清理掉当前设置的数据源,让默认的数据源不受影响DynamicDataSourceContextHolder.clearDataSourceType();}
}

(3)DataSourceConfig

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;@Configuration
public class DataSourceConfig {//主数据源@Value("${spring.datasource.master.jdbcUrl}")private String masterJdbcUrl;@Value("${spring.datasource.master.username}")private String masterUsername;@Value("${spring.datasource.master.password}")private String masterPassword;@Value("${spring.datasource.driver-class-name}")private String masterDriverClassName;@Value("${spring.datasource.master.name}")private String name;//从数据源1@Value("${spring.datasource.slave.jdbcUrl}")private String slaveJdbcUrl1;@Value("${spring.datasource.slave.username}")private String slaveUsername1;@Value("${spring.datasource.slave.password}")private String slavePassword1;@Value("${spring.datasource.driver-class-name}")private String slaveDriverClassName1;@Value("${spring.datasource.slave.name}")private String slaveName;//从数据源2@Value("${spring.datasource.slave2.jdbcUrl}")private String slaveJdbcUrl2;@Value("${spring.datasource.slave2.username}")private String slaveUsername2;@Value("${spring.datasource.slave2.password}")private String slavePassword2;@Value("${spring.datasource.driver-class-name}")private String slaveDriverClassName2;@Value("${spring.datasource.slave2.name}")private String slaveName2;//其他相关配置@Value("${spring.datasource.druid.initialSize}")private int initialSize;@Value("${spring.datasource.druid.minIdle}")private int minIdle;@Value("${spring.datasource.druid.maxWait}")private int maxWait;@Value("${spring.datasource.druid.filters}")private String filters;@Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}")private int timeBetweenEvictionRunsMillis;@Value("${spring.datasource.druid.minEvictableIdleTimeMillis}")private int minEvictableIdleTimeMillis;@Value("${spring.datasource.druid.validationQuery}")private String validationQuery;@Value("${spring.datasource.druid.testWhileIdle}")private boolean testWhileIdle;@Value("${spring.datasource.druid.testOnBorrow}")private boolean testOnBorrow;@Value("${spring.datasource.druid.testOnReturn}")private boolean testOnReturn;@Value("${spring.datasource.druid.poolPreparedStatements}")private boolean poolPreparedStatements;@Value("${spring.datasource.druid.maxPoolPreparedStatementPerConnectionSize}")private int maxPoolPreparedStatementPerConnectionSize;@Value("${spring.datasource.druid.timeBetweenLogStatsMillis}")private int timeBetweenLogStatsMillis;@Value("${spring.datasource.druid.keep-alive}")private boolean keepAlive;@Value("${spring.datasource.druid.connectionProperties}")private String connectionProperties;@Beanpublic DataSource masterDataSource() {return generateDataSource(masterJdbcUrl,masterUsername,masterPassword,masterDriverClassName,name);}@Bean@ConditionalOnProperty(prefix = "spring.datasource.slave", name = "enabled", havingValue = "true")public DataSource slaveDataSource1() {return generateDataSource(slaveJdbcUrl1,slaveUsername1,slavePassword1,slaveDriverClassName1,slaveName);}@Bean@ConditionalOnProperty(prefix = "spring.datasource.slave2", name = "enabled", havingValue = "true")public DataSource slaveDataSource2() {return generateDataSource(slaveJdbcUrl2,slaveUsername2,slavePassword2,slaveDriverClassName2,slaveName2);}private DruidDataSource generateDataSource(String url,String username,String password,String driverClassName,String name){DruidDataSource datasource = new DruidDataSource();datasource.setUrl(url);datasource.setUsername(username);datasource.setPassword(password);datasource.setDriverClassName(driverClassName);datasource.setName(name);datasource.setInitialSize(initialSize);datasource.setMinIdle(minIdle);datasource.setMaxWait(maxWait);datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);datasource.setValidationQuery(validationQuery);datasource.setTestWhileIdle(testWhileIdle);datasource.setTestOnBorrow(testOnBorrow);datasource.setTestOnReturn(testOnReturn);datasource.setPoolPreparedStatements(poolPreparedStatements);datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);datasource.setKeepAlive(keepAlive);try {datasource.setFilters(filters);} catch (SQLException e) {System.err.println("druid configuration initialization filter: " + e);}datasource.setConnectionProperties(connectionProperties);datasource.setTimeBetweenLogStatsMillis(timeBetweenLogStatsMillis);return datasource;}@Bean(name = "dynamicDataSource")@DependsOn({"masterDataSource", "slaveDataSource1", "slaveDataSource2"})  //如果不加这个,会报错:The dependencies of some of the beans in the application context form a cycle@Primarypublic DynamicDataSource dataSource(DataSource masterDataSource, DataSource slaveDataSource1, DataSource slaveDataSource2) {Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);targetDataSources.put(DataSourceType.BACKONE.name(), slaveDataSource1);targetDataSources.put(DataSourceType.BACKTWO.name(), slaveDataSource2);return new DynamicDataSource(masterDataSource, targetDataSources);}}

(4)DataSourceType

public enum DataSourceType {/*** 主库*/MASTER,/*** 从库1*/BACKONE,/*** 从库2*/BACKTWO;
}

(5)DynamicDataSource

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;import javax.sql.DataSource;
import java.util.Map;public class DynamicDataSource extends AbstractRoutingDataSource {public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {super.setDefaultTargetDataSource(defaultTargetDataSource);super.setTargetDataSources(targetDataSources);// afterPropertiesSet()方法调用时用来将targetDataSources的属性写入resolvedDataSources中的super.afterPropertiesSet();}/*** 根据Key获取数据源的信息*/@Overrideprotected Object determineCurrentLookupKey() {return DynamicDataSourceContextHolder.getDataSourceType();}}

(6)DynamicDataSourceContextHolder

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class DynamicDataSourceContextHolder {public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);/*** 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,*  所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。*/private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();/*** 设置数据源变量*/public static void setDataSourceType(String dataSourceType){log.info("切换到{}数据源", dataSourceType);CONTEXT_HOLDER.set(dataSourceType);}/*** 获取数据源变量*/public static String getDataSourceType(){return CONTEXT_HOLDER.get();}/*** 清空数据源变量*/public static void clearDataSourceType(){CONTEXT_HOLDER.remove();}}

3.使用

(1)调用从库1

/*** 调用从库1*/
@Component
@DataSource(value = DataSourceType.BACKONE)
public interface TestOneMapper {}

(2)调用从库2

/*** 调用从库2*/
@Component
@DataSource(value = DataSourceType.BACKTWO)
public interface TestTwoMapper {}

欢迎关注我的公众号

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/889282.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

视频推拉流EasyDSS无人机直播技术巡查焚烧、烟火情况

焚烧作为一种常见的废弃物处理方式&#xff0c;往往会对环境造成严重污染。因此&#xff0c;减少焚烧、推广绿色能源和循环经济成为重要措施。通过加强森林防灭火队伍能力建设与长效机制建立&#xff0c;各地努力减少因焚烧引发的森林火灾&#xff0c;保护生态环境。 巡察烟火…

K8S对接ceph的RBD块存储

1 PG数量限制问题 1.1 原因分析 1.还是老样子&#xff0c;先创建存储池&#xff0c;在初始化为rbd。 [rootceph141~]# ceph osd pool create wenzhiyong-k8s 128 128 Error ERANGE: pg_num 128 size 3 for this pool would result in 295 cumulative PGs per OSD (2067 tot…

React Router 6的学习

安装react-router-dom npm i react-router-dom 支持不同的路由创建 createBrowserRouter 特点 推荐使用的方式&#xff0c;基于 HTML5 的 History API。支持用户友好的 URL&#xff0c;无需 #。适用于生产环境的绝大多数场景。 适用 使用现代浏览器&#xff0c;支持 pus…

微信小程序web-view 嵌套h5界面 实现文件预览效果

实现方法&#xff1a;(这里我是在小程序里面单独加了一个页面用来下载预览文件) 安装 使用方法请参考文档 npm 安装 npm install weixin-js-sdk import wx from weixin-js-sdk预览 h5界面代码 <u-button click"onclick" type"primary" :loading"…

HTTP 状态码大全

常见状态码 200 OK # 客户端请求成功 400 Bad Request # 客户端请求有语法错误 不能被服务器所理解 401 Unauthorized # 请求未经授权 这个状态代码必须和WWW- Authenticate 报头域一起使用 403 Forbidden # 服务器收到请求但是拒绝提供服务 404 Not Found # 请求资源不存…

一文详解TCP协议 [图文并茂, 明了易懂]

欢迎来到啊妮莫的学习小屋! 目录 什么是TCP协议 TCP协议特点✨ TCP报文格式 三次握手和四次挥手✨ 可靠性 效率性 基于字节流✨ 基于TCP的应用层协议 什么是TCP协议 TCP(传输控制协议, Transmission Control Protocol) 是一种面向连接的, 可靠的, 基于字节流的传输层通…

在Linux(ubuntu22.04)搭建rust开发环境

1.安装rust 1.安装curl: sudo apt install curl 2.安装rust最新版 curl --proto ‘https’ --tlsv1.2 https://sh.rustup.rs -sSf | sh 安装完成后出现&#xff1a;Rust is installed now. Great! 重启当前shell即可 3.检验是否安装成功 rustc --version 结果出现&…

UnityShaderLab 实现程序化形状(一)

1.实现一个长宽可变的矩形&#xff1a; 代码&#xff1a; fixed4 frag (v2f i) : SV_Target{return saturate(length(saturate(abs(i.uv - 0.5)-0.13)))/0.03;} 2.实现一个半径可变的圆形&#xff1a; 代码&#xff1a; fixed4 frag (v2f i) : SV_Target{return (distance(a…

如何解决压测过程中JMeter堆内存溢出问题

如何解决压测过程中JMeter堆内存溢出问题 背景一、为什么会堆内存溢出&#xff1f;二、解决堆内存溢出措施三、堆内存参数应该怎么调整&#xff1f;四、堆内存大小配置建议 背景 Windows环境下使用JMeter压测运行一段时间后&#xff0c;JMeter日志窗口报错“java.lang.OutOfMe…

宽字节注入

尽管现在呼吁所有的程序都使用unicode编码&#xff0c;所有的网站都使用utf-8编码&#xff0c;来一个统一的国际规范。但仍然有很多&#xff0c;包括国内及国外&#xff08;特别是非英语国家&#xff09;的一些cms&#xff0c;仍然使用着自己国家的一套编码&#xff0c;比如gbk…

Web APIsPIs第1章

WebApi阶段学习什么&#xff1f; WebApi是浏览器提供的一组接口 使用 JavaScript 去操作页面文档 和 浏览器 什么是 API API: 应用程序接口&#xff08;Application Programming Interface&#xff09; 接口&#xff1a;本质上就是各种函数&#xff0c;无需关心内部如何实现…

android——录制屏幕

录制屏幕 1、界面 2、核心代码 import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent import android.app.Service import android.content.Context import android.content.Intent import android.graphics.Bi…

【Excel学习记录】01-认识Excel

1.之前的优秀软件Lotus-1-2-3 默认公式以等号开头 兼容Lotus-1-2-3的公式写法&#xff0c;不用写等号 &#xff1a; 文件→选项→高级→勾选&#xff1a;“转换Lotus-1-2-3公式(U)” 备注&#xff1a;对于大范围手动输入公式可以使用该选项&#xff0c;否则请不要勾选&#x…

短视频矩阵抖音SEO源码OEM独立部署

短视频优化矩阵源码涉及对抖音平台上的视频内容进行筛选与排序&#xff0c;目的是增强其在搜索引擎中的可见度&#xff0c;以便更多用户能够浏览到这些视频。而抖音SEO优化系统则是通过构建一个分析框架&#xff0c;来解析抖音上的用户数据、视频信息及标签等元素&#xff0c;并…

MySQL——buffer poll

为什么要有buffer poll&#xff1f; 如果没有buffer poll&#xff0c;每次读取数据的时候都是从磁盘上读的&#xff0c;这样效率是很差的的。 所以有了提高效率的方式&#xff0c;就加上了一个缓存——buffer poll 所以&#xff0c;当我们读取数据的时候就有以下的方式 当读…

生产慎用之调试日志对空间矢量数据批量插入的性能影响-以MybatisPlus为例

目录 前言 一、一些缘由 1、性能分析 二、插入方式调整 1、批量插入的实现 2、MP的批量插入实现 3、日志的配置 三、默认处理方式 1、基础程序代码 2、执行情况 四、提升调试日志等级 1、在logback中进行设置 2、提升后的效果 五、总结 前言 在现代软件开发中&#xff0c;性能优…

元宇宙时代的社交平台:Facebook的愿景与实践

随着科技的不断进步&#xff0c;元宇宙&#xff08;Metaverse&#xff09;这一概念逐渐走进了人们的视野。作为全球最大的社交平台之一&#xff0c;Facebook&#xff08;现Meta&#xff09;在这场元宇宙革命中扮演着重要角色。Meta不仅在不断扩展其社交平台的边界&#xff0c;还…

C# 小案例(IT资产管理系统)

开发工具&#xff1a;visual studio 2022 语言&#xff1a;C# 数据库&#xff1a;Sql Server 2008 页面展示 一、登录 二、主窗体 三、用户管理 四、资产管理 五、关于 Java版地址&#xff1a;基于若依开发物品管理系统(springbootvue)_若依物品管理系统-CSDN博客 Python版…

分布式日志系统设计

一、分布式日志系统定义 分布式日志系统是一种用于收集、存储和分析大规模分布式系统日志的系统。它可以帮助开发人员和系统管理员实时监控和调试系统&#xff0c;提高系统可靠性和可用性&#xff0c;同时也可以用于日志分析和故障排查。 二、简单设计思路 日志收集&#xff…

敏捷开发04:Scrum 中的 Product Backlog(产品待办列表) 详细介绍

Product Backlog 产品待办列表 在计划开发产品功能时&#xff0c;都希望产品功能上线后&#xff0c;用户能够喜欢并经常使用。 因此在开发产品新功能时&#xff0c;就要衡量哪些产品需求是对用户最有价值&#xff0c;这是最应该思考的问题。 然后把这些有价值的需求集合放在一…