日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

SpringBoot多数据源(主从数据源)配置

發布時間:2023/12/3 javascript 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringBoot多数据源(主从数据源)配置 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

🎶前言

學習springboot配置多數據源,先回顧一下springboot配置單數據源的方式
SpringBoot配置mybatis-mysql數據源

🔠主從數據源搭建

項目依賴

本次記錄多數據源配置主要是通過druid + mybatis plus + aop的形式實現的,mybatis plus是一個很方便的數據庫操作框架,自己也有實現多數據源的jar包,這里沒有使用她封裝的方法,主要是學習所以是自行實現了一遍簡單的多數據源配置和動態切換數據源。

<!-- mybatis-plus多數據源配置jar --> <dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId> </dependency>

使用到的依賴

<dependencies><!-- druid數據連接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId></dependency><!-- mybatis plus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId></dependency><!-- spring-aop --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!-- springboot配置依賴 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><!-- mysql驅動 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency> </dependencies>

Yml文件配置數據源

這里可以看到數據源配置屬性路徑并非spring.datasource, 這里主要是想通過學習spring-boot配置文件自動裝配, 來獲取配置并初始化數據源。

utmost:# 主從數據源配置datasource:dynamic:master:driverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.92.10:3306/utmost_01?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8userName: rootpassword: rootslave:enabled: true # 是否啟用從數據源driverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.92.10:3306/utmost_02?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8userName: rootpassword: root @Getter @Setter @ConfigurationProperties(prefix = UtmostDataSourceProperties.PREFIX) public class UtmostDataSourceProperties {/*** 配置前綴*/public static final String PREFIX = "utmost.datasource.dynamic";/*** master數據源配置前綴*/public static final String MASTER_PREFIX = "utmost.datasource.dynamic.master";/*** slave數據源配置前綴*/public static final String SLAVE_PREFIX = "utmost.datasource.dynamic.slave";/*** 設置默認數據庫, 默認master*/public String primary = "master";/*** 設置啟用數據源, 默認true*/public boolean enabled = true;/*** 主數據源*/public SingleDataSourceProperty master;/*** 從數據源*/public SingleDataSourceProperty slave; } @Data @Accessors(chain = true) public class SingleDataSourceProperty {/*** JDBC driver*/private String driverClassName;/*** JDBC 數據庫地址*/private String url;/*** JDBC 用戶名*/private String userName;/*** JDBC 用戶密碼*/private String password; }

怎么通過UtmostDataSourceProperties類來獲取屬性, 主要通過@ConfigurationProperties注解實現, 前面依賴中引入了spring-boot-configuration-processor依賴, 在使用yml配置數據源時就會出現一定的提示作用。這是因為在打包編譯的時候會生成一個spring-configuration-metadata.json文件,這里就不贅述了,先了解到這是springboot幫助我們生成的作用于提示的文件就可以了。

mybatis-plus配置

# mybatis-plus 配置 mybatis-plus:configuration:# 開啟駝峰map-underscore-to-camel-case: true# 關閉一級緩存local-cache-scope: statement# 關閉二級緩存cache-enabled: false# sql xml文件映射路徑mapper-locations: classpath*:/mapper/*.xml# MyBaits 別名包掃描路徑,通過該屬性可以給包中的類注冊別名type-aliases-package: com.zy.utmost.entity

數據源裝配

數據源配置類

@Slf4j @Configuration @AllArgsConstructor @EnableConfigurationProperties(UtmostDataSourceProperties.class) @ConditionalOnProperty(prefix = UtmostDataSourceProperties.PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true) public class UtmostDataSourceAutoConfiguration {private final UtmostDataSourceProperties utmostDataSourceProperties;/*** 主數據源(這里配置寫的繁瑣一點, 可根據個人喜好進行簡化.)** @return DataSource*/@Bean(name = "masterDataSource")@ConfigurationProperties(UtmostDataSourceProperties.MASTER_PREFIX)public DataSource masterDataSource() {SingleDataSourceProperty master = utmostDataSourceProperties.master;DruidDataSource druidDataSource = new DruidDataSource();druidDataSource.setName(DataSourceConstants.MASTER);druidDataSource.setDriverClassName(master.getDriverClassName());druidDataSource.setUrl(master.getUrl());druidDataSource.setUsername(master.getUserName());druidDataSource.setPassword(master.getPassword());return druidDataSource;}/*** 從 數據源(這里配置寫的繁瑣一點, 可根據個人喜好進行簡化.)** @return DataSource*/@Bean(name = "slaveDataSource")@ConfigurationProperties(UtmostDataSourceProperties.SLAVE_PREFIX)@ConditionalOnProperty(prefix = UtmostDataSourceProperties.SLAVE_PREFIX, name = "enabled", havingValue = "true")public DataSource slaveDataSource() {SingleDataSourceProperty slave = utmostDataSourceProperties.slave;DruidDataSource druidDataSource = new DruidDataSource();druidDataSource.setName(DataSourceConstants.SLAVE);druidDataSource.setDriverClassName(slave.getDriverClassName());druidDataSource.setUrl(slave.getUrl());druidDataSource.setUsername(slave.getUserName());druidDataSource.setPassword(slave.getPassword());return druidDataSource;}/*** 動態數據源** @return DynamicDataSource*/@Bean@Primarypublic DynamicDataSource dynamicDataSource() {Map<Object, Object> targetMap = new HashMap<>(2);targetMap.put(DataSourceConstants.MASTER, masterDataSource());targetMap.put(DataSourceConstants.SLAVE, slaveDataSource());DynamicDataSource dynamicDataSource = new DynamicDataSource(masterDataSource(), targetMap);log.info("動態數據源裝配完成...");return dynamicDataSource;} }

動態數據源實現類

通過繼承重寫AbstractRoutingDataSource 數據源路由來實現數據源動態切換的功能.

public class DynamicDataSource extends AbstractRoutingDataSource {/*** 使用線程切換數據源*/private static ThreadLocal<String> contextHandler = new ThreadLocal<>();/*** 數據源key集合*/private static List<Object> dataSourceKeys = new ArrayList<>();/*** 配置數據源** @param defaultDataSource 主數據源* @param targetDataSourceMap 其他數據源集合*/public DynamicDataSource(DataSource defaultDataSource, Map<Object, Object> targetDataSourceMap) {super.setDefaultTargetDataSource(defaultDataSource);super.setTargetDataSources(targetDataSourceMap);super.afterPropertiesSet();// 初始化所有數據源的keyaddAllDataSourceKeys(targetDataSourceMap.keySet());}public static void setDataSourceKeys(String key) {contextHandler.set(key);}public static ThreadLocal<String> getDataSourceKeys() {return contextHandler;}public static void removeDataSourceKeys() {contextHandler.remove();}public static boolean containsDataSourceKeys(String key) {return dataSourceKeys.contains(key);}public static boolean addAllDataSourceKeys(Collection<? extends Object> keys) {return dataSourceKeys.addAll(keys);}@Overrideprotected Object determineCurrentLookupKey() {return contextHandler.get();} }

數據源切換注解

/*** 注解命名主要是為了好記所以直接使用了DataSource, 在使用時會發現有很* 多類都是以DataSource命名, 使用時需要注意.* @author yanzy*/ @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DataSource {String value() default ""; }

數據源切換實現

/*** 實現注解織入切換數據源** @author yanzy* @date 2021/6/10 23:38* @since v1.0*/ @Aspect @Order(-10) @Component public class DataSourceAspect {private Logger logger = LoggerFactory.getLogger(DataSourceAspect.class);/*** - @within掃描類注解, @annotation掃描方法上注解* 定義切面*/@Pointcut("@annotation(com.zy.utmost.annotation.DataSource) || @within(com.zy.utmost.annotation.DataSource)")public void annotationPointCut() {}/*** 前置事件 (方法前切換數據源)* @param point 織入點* @param dataSource 注解實例*/@Before("annotationPointCut() && @annotation(dataSource))")public void beforeMethod(JoinPoint point, DataSource dataSource) {switchDataSource(point, dataSource);}/*** 前置事件 (類前切換數據源)* @param point 織入點* @param dataSource 注解實例*/@Before("annotationPointCut() && @within(dataSource))")public void beforeClass(JoinPoint point, DataSource dataSource) {switchDataSource(point, dataSource);}private void switchDataSource(JoinPoint point,DataSource dataSource) {String key = dataSource.value();if (!DynamicDataSource.containsDataSourceKeys(key)) {logger.debug("數據源切換失敗: [{}] - 數據源不存在, 自動使用默認數據源.", key);} else {DynamicDataSource.setDataSourceKeys(key);logger.debug("數據源切換成功: [{}] - 已切換至 - [{}] - 數據源.", point.getSignature().getName(), key);}}/*** 后置增強 (方法/類執行完畢后,將數據源切回默認)** @param point 織入點*/@After("annotationPointCut()")public void after(JoinPoint point) {if (null != DynamicDataSource.getDataSourceKeys()) {DynamicDataSource.removeDataSourceKeys();logger.debug("數據源切換成功: 切換為主數據源.");}} }

搭建完測試

測試使用的crud類就不附上代碼了, 直接使用spring-boot-test來給數據庫插入數據, 驗證一下數據源是否可以正常切換.

數據庫

首先這里使用了兩個數據庫, 都創建了utmost這個數據庫實例并創建有sys_user表.

service實現類(方法增加注解切換數據源)

@Service public class SysUserServiceImpl implements SysUserService {@Resourceprivate SysUserMapper sysUserMapper;// 主庫插入@Overridepublic Integer insertUserMaster(SysUser sysUser) {return sysUserMapper.insert(sysUser);}// 從庫插入@Override@DataSource(value = DataSourceConstants.SLAVE)public Integer insertUserSlave(SysUser sysUser) {return sysUserMapper.insert(sysUser);} }

📣測試類

@SpringBootTest public class SysUserTableTest {@Autowiredprivate SysUserService sysUserService;@Testpublic void insertByMaster() {SysUser sysUser = new SysUser();sysUser.setUserName("admin");sysUser.setLoginName("admin");sysUser.setPassword("admin");sysUserService.insertUserMaster(sysUser);}@Testpublic void insertBySlave() {SysUser sysUser = new SysUser();sysUser.setUserName("admin");sysUser.setLoginName("admin");sysUser.setPassword("admin");sysUserService.insertUserSlave(sysUser);} }

測試主庫插入, 不標注注解時, 默認使用主庫.

測試從庫插入, 調用使用了切換數據源注解得到方法

類標注注解測試

@Service @DataSource(value = DataSourceConstants.SLAVE) public class SysUserServiceImpl implements SysUserService {@Resourceprivate SysUserMapper sysUserMapper;@Overridepublic Integer insertUserMaster(SysUser sysUser) {return sysUserMapper.insert(sysUser);}@Overridepublic Integer insertUserSlave(SysUser sysUser) {return sysUserMapper.insert(sysUser);} }

調用insertUserMaster, 驗證數據源是否切換成功.

💯總結

好啦~ 以上主要記錄一下自己在學習過程中是如何配置多數據源的(嚴格來說代碼中的寫法應該是主從數據源 嘿嘿)。
一般主從數據源主要是為了做讀寫分離的,后面學習總結完讀寫分離操作后在進行分享記錄啦~~

總結

以上是生活随笔為你收集整理的SpringBoot多数据源(主从数据源)配置的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。