mybatis-plus動態(tài)數(shù)據(jù)源讀寫分離方式
1、背景
在實際項目的開發(fā)過程中,一定會存在主庫與從庫的分布式模式,主庫進(jìn)行增刪改,從庫進(jìn)行查詢。
這樣可以保證對不同的數(shù)據(jù)庫進(jìn)行操作,減少對數(shù)據(jù)庫的壓力。
2、動態(tài)數(shù)據(jù)源
創(chuàng)建DynamicDatasourceService
import com.jiuqi.grid.collection.entity.datasource.DataSourceDTO;
import java.util.Set;
public interface DynamicDatasourceService {
/**
* 獲取所有數(shù)據(jù)源
*
* @return
*/
Set<String> datasources();
/**
* 添加數(shù)據(jù)源
*
* @param dto 數(shù)據(jù)源信息
* @return
*/
Set<String> add(DataSourceDTO dto);
/**
* 移除數(shù)據(jù)源
*
* @param name 連接池名稱
*/
void remove(String name);
}實現(xiàn)DynamicDatasourceService
package com.jiuqi.grid.collection.service.impl;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.jiuqi.grid.collection.entity.datasource.DataSourceDTO;
import com.jiuqi.grid.collection.service.DynamicDatasourceService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.util.Set;
@Service
public class DynamicDatasourceServiceImpl implements DynamicDatasourceService {
private final DataSource dataSource;
private final DefaultDataSourceCreator dataSourceCreator;
public DynamicDatasourceServiceImpl(
DataSource dataSource, DefaultDataSourceCreator dataSourceCreator) {
this.dataSource = dataSource;
this.dataSourceCreator = dataSourceCreator;
}
/**
* 獲取所有數(shù)據(jù)源
*
* @return
*/
@Override
public Set<String> datasources() {
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
return ds.getDataSources().keySet();
}
/**
* 添加數(shù)據(jù)源
*
* @param dto
* @return
*/
@Override
public Set<String> add(DataSourceDTO dto) {
DataSourceProperty dataSourceProperty = new DataSourceProperty();
BeanUtils.copyProperties(dto, dataSourceProperty);
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty);
ds.addDataSource(dto.getPollName(), dataSource);
return ds.getDataSources().keySet();
}
/**
* 刪除數(shù)據(jù)源
*
* @param name
*/
@Override
public void remove(String name) {
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
ds.removeDataSource(name);
}
}2.1添加數(shù)據(jù)源
我這里是讀取的配置文件里的用戶名、密碼等數(shù)據(jù)源的鏈接
public void addDatasource(String tenant) {
if (dynamicDatasourceService.datasources().contains(tenant)) {
return;
}
DataSourceDTO datasourceDTO = new DataSourceDTO();
//庫名
datasourceDTO.setPollName(tenant);
//鏈接信息 讀取配置文件的主庫信息
datasourceDTO.setDriverClassName(sqlDataSource.getDriverClassName());
//替換數(shù)據(jù)庫
if (StringUtils.isEmpty(sqlDataSource.getUrl())) {
throw new RuntimeException("配置文件讀取失敗");
}
String url = sqlDataSource.getUrl();
url = url.replace("grid_test", tenant);
datasourceDTO.setUrl(url);
datasourceDTO.setUsername(sqlDataSource.getUsername());
datasourceDTO.setPassword(sqlDataSource.getPassword());
dynamicDatasourceService.add(datasourceDTO);
}2.2數(shù)據(jù)源
調(diào)用上面的addDatasource()方法,數(shù)據(jù)源就會創(chuàng)建成功,這里要注意的是,每一次增刪改查都需要調(diào)用此方法,以防數(shù)據(jù)源不存在。
3、分庫查詢
創(chuàng)建新的數(shù)據(jù)源目的就是為了可以進(jìn)行分庫操作。
分庫操作步驟如下:
3.1添加配置類
package com.jiuqi.grid.collection.dsprocessor;
import com.baomidou.dynamic.datasource.processor.DsHeaderProcessor;
import com.baomidou.dynamic.datasource.processor.DsProcessor;
import com.baomidou.dynamic.datasource.processor.DsSessionProcessor;
import com.baomidou.dynamic.datasource.processor.DsSpelExpressionProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 注冊動態(tài)數(shù)據(jù)源解析器
*/
@Configuration
public class MyDynamicDataSourceConfig {
@Bean
public DsProcessor dsProcessor() {
DsMapProcessor mapProcessor = new DsMapProcessor();
DsHeaderProcessor headerProcessor = new DsHeaderProcessor();
DsSessionProcessor sessionProcessor = new DsSessionProcessor();
DsSpelExpressionProcessor spelExpressionProcessor = new DsSpelExpressionProcessor();
mapProcessor.setNextProcessor(headerProcessor);
headerProcessor.setNextProcessor(sessionProcessor);
sessionProcessor.setNextProcessor(spelExpressionProcessor);
return mapProcessor;
}
}package com.jiuqi.grid.collection.dsprocessor;
import com.baomidou.dynamic.datasource.processor.DsProcessor;
import java.util.Map;
import com.jiuqi.grid.collection.consts.SQLConstants;
import com.jiuqi.grid.collection.dto.common.Address3DTO;
import com.jiuqi.grid.collection.dto.data.CollectionDataPageParam;
import com.jiuqi.grid.collection.entity.CollectionDataDO;
import org.aopalliance.intercept.MethodInvocation;
/**
* 通過params map中獲取數(shù)據(jù)源標(biāo)識
*
* @author songlude
*/
public class DsMapProcessor extends DsProcessor {
/**
* 抽象匹配條件 匹配才會走當(dāng)前執(zhí)行器否則走下一級執(zhí)行器
*
* @param key DS注解里的內(nèi)容
* @return 是否匹配
*/
@Override
public boolean matches(String key) {
return key.equals("#" + SQLConstants.EXEC_DATASOURCE);
}
/**
* 抽象最終決定數(shù)據(jù)源
*
* @param invocation 方法執(zhí)行信息
* @param key DS注解里的內(nèi)容
* @return 數(shù)據(jù)源名稱
*/
@Override
public String doDetermineDatasource(MethodInvocation invocation, String key) {
Object[] arguments = invocation.getArguments();
Object argument = arguments[0];
if (argument instanceof Map) {
Map<String, Object> params = (Map<String, Object>) argument;
Object value = params.get(SQLConstants.EXEC_DATASOURCE);
return value == null ? null : value.toString();
} else if (argument instanceof CollectionDataPageParam) {
CollectionDataPageParam collectionDataPageParam = (CollectionDataPageParam) argument;
return collectionDataPageParam.getGRID_DATASOURCE();
} else if (argument instanceof CollectionDataDO) {
CollectionDataDO collectionDataDO = (CollectionDataDO) argument;
return collectionDataDO.getGRID_DATASOURCE();
} else if (argument instanceof Address3DTO) {
Address3DTO address3DTO = (Address3DTO) argument;
return address3DTO.getGRID_DATASOURCE();
}
return null;
}
}
這里要注意需要把“argument”進(jìn)行類型的判斷,argument 就是你查詢Mapper的參數(shù),這里我獲取的是argument[0],則Mapper參數(shù)的位置在第一個。
3.2 添加數(shù)據(jù)源查詢
通過@DS注解來指定數(shù)據(jù)源,在配置類中指定了以#開頭
@DS("#GRID_DATASOURCE")
@UpdateProvider(type = QueryProvider.class, method = "createDatabase")
void createDatabase(Map<String, Object> params);這樣就可以開啟你的動態(tài)數(shù)據(jù)源,分庫查詢啦。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Springboot?hibernate-validator?6.x快速校驗示例代碼
這篇文章主要介紹了Springboot?hibernate-validator?6.x校驗,本文以6.2.1.Final版本為例解決了log4j版本的漏洞問題,通過實例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-12-12
Java中DataInputStream和DataOutputStream的使用方法
這篇文章主要介紹了Java中DataInputStream和DataOutputStream的使用方法,通過創(chuàng)建對象展開具體的內(nèi)容介紹,需要的小伙伴可以參考一下2022-05-05
IntelliJ IDEA Run時報“無效的源發(fā)行版:16“錯誤問題及解決方法
這篇文章主要介紹了IntelliJ IDEA Run時報“無效的源發(fā)行版:16“錯誤問題及解決方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-05-05
java如何實現(xiàn)postman中用x-www-form-urlencoded參數(shù)的請求
在Java開發(fā)中,模擬Postman發(fā)送x-www-form-urlencoded類型的請求是一個常見需求,本文主要介紹了如何在Java中實現(xiàn)這一功能,首先,需要通過導(dǎo)入http-client包來創(chuàng)建HTTP客戶端,接著,利用該客戶端發(fā)送Post請求2024-09-09
SpringBoot最新定時任務(wù)的7種實現(xiàn)方案
在現(xiàn)代應(yīng)用中,定時任務(wù)是一個非常常見的需求,本文將通過7種方式講解如何在SpringBoot中實現(xiàn)定時任務(wù),包括使用@Scheduled注解、ScheduledExecutorService、Quartz、SpringTaskScheduler、Redis、XXL-JOB和Elastic-Job等,各有優(yōu)缺點,選擇時應(yīng)根據(jù)實際需求進(jìn)行考慮2024-12-12

