SpringBoot框架DataSource多數(shù)據(jù)源配置方式
新增數(shù)據(jù)源填入xml文件
這里使用的是新搭建的一個(gè)架子,依賴(lài)什么的 就自己Maven工廠(chǎng)去下載吧
我是按照若依的架子搭建的,之前弄過(guò)一次,失敗了哈哈哈
進(jìn)入正題
1、導(dǎo)入依賴(lài)
2、在配置文件中添加數(shù)據(jù)源信息
3、新建 自定義注解 DataSource
4、新建 DynamicDataSource
繼承Spring boot提供的AbstractRoutingDataSource 根據(jù)用戶(hù)定義的規(guī)則選擇當(dāng)前的數(shù)據(jù)源
它的抽象方法 determineCurrentLookupKey() 決定使用哪個(gè)數(shù)據(jù)源。
全部代碼
/** * 動(dòng)態(tài)數(shù)據(jù)源 * @program: LanAn * @description: DynamicDataSource * @author: LanAn * @create: 2022-08-17 15:33 **/ public class DynamicDataSource extends AbstractRoutingDataSource { public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) { super.setDefaultTargetDataSource(defaultTargetDataSource); super.setTargetDataSources(targetDataSources); super.afterPropertiesSet(); } /** * 根據(jù)用戶(hù)定義的規(guī)則選擇當(dāng)前的數(shù)據(jù)源] * @return: java.lang.Object * @Author: LanAn * @Date: 2022/8/17 0017 */ @Override protected Object determineCurrentLookupKey() { return DynamicDataSourceContextHolder.getDataSourceType(); } }
5、新建DynamicDataSourceContextHolder做動(dòng)態(tài)數(shù)據(jù)源切換處理
public class DynamicDataSourceContextHolder { public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class); /** * 使用ThreadLocal維護(hù)變量,ThreadLocal為每個(gè)使用該變量的線(xiàn)程提供獨(dú)立的變量副本, * 所以每一個(gè)線(xiàn)程都可以獨(dú)立地改變自己的副本,而不會(huì)影響其它線(xiàn)程所對(duì)應(yīng)的副本。 */ private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>(); /** * 設(shè)置數(shù)據(jù)源的變量 */ public static void setDataSourceType(String dsType) { log.info("切換到{}數(shù)據(jù)源", dsType); CONTEXT_HOLDER.set(dsType); } /** * 獲得數(shù)據(jù)源的變量 */ public static String getDataSourceType() { return CONTEXT_HOLDER.get(); } /** * 清空數(shù)據(jù)源變量 */ public static void clearDataSourceType() { CONTEXT_HOLDER.remove(); } }
6、新建DataSourceType添加對(duì)應(yīng)的數(shù)據(jù)庫(kù)枚舉
新增數(shù)據(jù)源的話(huà) 在下方繼續(xù)添加枚舉
全部代碼
public enum DataSourceType { /** * 主庫(kù) */ MASTER, /** * 從庫(kù) */ SLAVE }
7、新增DruidConfig配置類(lèi)配置讀配置源方法
有多個(gè)數(shù)據(jù)源可以在下方照葫蘆畫(huà)瓢 哈哈哈
配置類(lèi)全部代碼
public class DruidConfig { /** * 主庫(kù)數(shù)據(jù)源 * @Param: [druidProperties] * @return: javax.sql.DataSource * @Author: LanAn * @Date: 2022/8/17 0017 */ @Bean @ConfigurationProperties("spring.datasource.druid.master") public DataSource masterDataSource(DruidProperties druidProperties) { DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); return druidProperties.dataSource(dataSource); } /** * 從庫(kù)數(shù)據(jù)源 * @Param: [druidProperties] * @return: javax.sql.DataSource * @Author: LanAn * @Date: 2022/8/17 0017 */ @Bean @ConfigurationProperties("spring.datasource.druid.slave") @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true") public DataSource slaveDataSource(DruidProperties druidProperties) { DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); return druidProperties.dataSource(dataSource); } @Bean(name = "dynamicDataSource") @Primary public DynamicDataSource dataSource(DataSource masterDataSource) { Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource); setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource"); return new DynamicDataSource(masterDataSource, targetDataSources); } /** * 設(shè)置數(shù)據(jù)源 * * @param targetDataSources 備選數(shù)據(jù)源集合 * @param sourceName 數(shù)據(jù)源名稱(chēng) * @param beanName bean名稱(chēng) */ public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName) { try { DataSource dataSource = SpringUtils.getBean(beanName); targetDataSources.put(sourceName, dataSource); } catch (Exception e) { } } /** * 去除監(jiān)控頁(yè)面底部的廣告 */ @SuppressWarnings({"rawtypes", "unchecked"}) @Bean @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true") public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties) { // 獲取web監(jiān)控頁(yè)面的參數(shù) DruidStatProperties.StatViewServlet config = properties.getStatViewServlet(); // 提取common.js的配置路徑 String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*"; String commonJsPattern = pattern.replaceAll("\\*", "js/common.js"); final String filePath = "support/http/resources/js/common.js"; // 創(chuàng)建filter進(jìn)行過(guò)濾 Filter filter = new Filter() { @Override public void init(javax.servlet.FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { chain.doFilter(request, response); // 重置緩沖區(qū),響應(yīng)頭不會(huì)被重置 response.resetBuffer(); // 獲取common.js String text = Utils.readFromResource(filePath); // 正則替換banner, 除去底部的廣告信息 text = text.replaceAll("<a.*?banner\"></a><br/>", ""); text = text.replaceAll("powered.*?shrek.wang</a>", ""); response.getWriter().write(text); } @Override public void destroy() { } }; FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(filter); registrationBean.addUrlPatterns(commonJsPattern); return registrationBean; } }
嘶~~~~少了倆配置,補(bǔ)到后邊吧
8、新建 DruidProperties druid配置屬性
@Configuration public class DruidProperties { @Value("${spring.datasource.druid.initialSize}") private int initialSize; @Value("${spring.datasource.druid.minIdle}") private int minIdle; @Value("${spring.datasource.druid.maxActive}") private int maxActive; @Value("${spring.datasource.druid.maxWait}") private int maxWait; @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}") private int timeBetweenEvictionRunsMillis; @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}") private int minEvictableIdleTimeMillis; @Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}") private int maxEvictableIdleTimeMillis; @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; public DruidDataSource dataSource(DruidDataSource datasource) { /** 配置初始化大小、最小、最大 */ datasource.setInitialSize(initialSize); datasource.setMaxActive(maxActive); datasource.setMinIdle(minIdle); /** 配置獲取連接等待超時(shí)的時(shí)間 */ datasource.setMaxWait(maxWait); /** 配置間隔多久才進(jìn)行一次檢測(cè),檢測(cè)需要關(guān)閉的空閑連接,單位是毫秒 */ datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); /** 配置一個(gè)連接在池中最小、最大生存的時(shí)間,單位是毫秒 */ datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis); /** * 用來(lái)檢測(cè)連接是否有效的sql,要求是一個(gè)查詢(xún)語(yǔ)句,常用select 'x'。如果validationQuery為null,testOnBorrow、testOnReturn、testWhileIdle都不會(huì)起作用。 */ datasource.setValidationQuery(validationQuery); /** 建議配置為true,不影響性能,并且保證安全性。申請(qǐng)連接的時(shí)候檢測(cè),如果空閑時(shí)間大于timeBetweenEvictionRunsMillis,執(zhí)行validationQuery檢測(cè)連接是否有效。 */ datasource.setTestWhileIdle(testWhileIdle); /** 申請(qǐng)連接時(shí)執(zhí)行validationQuery檢測(cè)連接是否有效,做了這個(gè)配置會(huì)降低性能。 */ datasource.setTestOnBorrow(testOnBorrow); /** 歸還連接時(shí)執(zhí)行validationQuery檢測(cè)連接是否有效,做了這個(gè)配置會(huì)降低性能。 */ datasource.setTestOnReturn(testOnReturn); return datasource; } }
9、多數(shù)據(jù)源處理
/** * @program: LanAn * 多數(shù)據(jù)源處理 * @description: DataSourceAspect * @author: LanAn * @create: 2022-08-17 14:21 **/ @Aspect @Order(1) @Component public class DataSourceAspect { protected Logger logger = LoggerFactory.getLogger(getClass()); @Pointcut("@annotation(com.lanan.common.annotation.DataSource)" + "|| @within(com.lanan.common.annotation.DataSource)") public void dsPointCut() { } @Around("dsPointCut()") public Object around(ProceedingJoinPoint point) throws Throwable { DataSource dataSource = getDataSource(point); if (StringUtils.isNotNull(dataSource)) { DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name()); } try { return point.proceed(); } finally { // 銷(xiāo)毀數(shù)據(jù)源 在執(zhí)行方法之后 DynamicDataSourceContextHolder.clearDataSourceType(); } } /** * 獲取需要切換的數(shù)據(jù)源 */ public DataSource getDataSource(ProceedingJoinPoint point) { MethodSignature signature = (MethodSignature) point.getSignature(); DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class); if (Objects.nonNull(dataSource)) { return dataSource; } return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class); } }
10、配置完成 使用方法
在實(shí)現(xiàn)類(lèi)上直接使用@DataSource注解
可以在方法上指定使用某個(gè)數(shù)據(jù)源
完成!?。。。。。?/p>
總結(jié)
ok!到這里就完成了,啟動(dòng)頁(yè)沒(méi)有報(bào)錯(cuò)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解Java中的File文件類(lèi)以及FileDescriptor文件描述類(lèi)
在Java中File類(lèi)可以用來(lái)新建文件和目錄對(duì)象,而FileDescriptor類(lèi)則被用來(lái)表示文件或目錄的可操作性,接下來(lái)我們就來(lái)詳解Java中的File文件類(lèi)以及FileDescriptor文件描述類(lèi)2016-06-06SpingMvc復(fù)雜參數(shù)傳收總結(jié)
這篇文章主要為大家介紹了SpingMvc復(fù)雜參數(shù)傳收總結(jié),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08Spring如何解決單例bean線(xiàn)程不安全的問(wèn)題
這篇文章主要介紹了Spring如何解決單例bean線(xiàn)程不安全的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12詳解Spring 中如何控制2個(gè)bean中的初始化順序
本篇文章主要介紹了Spring 中如何控制2個(gè)bean中的初始化順序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10為什么wait和notify必須放在synchronized中使用
這篇文章主要介紹了為什么wait和notify必須放在synchronized中使用,文章圍繞主題的相關(guān)問(wèn)題展開(kāi)詳細(xì)介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考以參考一下2022-05-05Java利用HttpClient模擬POST表單操作應(yīng)用及注意事項(xiàng)
本文主要介紹JAVA中利用HttpClient模擬POST表單操作,希望對(duì)大家有所幫助。2016-04-04Mybatis?連接mysql數(shù)據(jù)庫(kù)底層運(yùn)行的原理分析
這篇文章主要介紹了Mybatis?連接mysql數(shù)據(jù)庫(kù)底層運(yùn)行的原理分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03SpringBoot?mybatis-plus使用json字段實(shí)戰(zhàn)指南
在現(xiàn)代應(yīng)用開(kāi)發(fā)中經(jīng)常會(huì)使用JSON格式存儲(chǔ)和傳輸數(shù)據(jù),為了便捷地處理數(shù)據(jù)庫(kù)中的JSON字段,MyBatis-Plus提供了強(qiáng)大的JSON處理器,這篇文章主要給大家介紹了關(guān)于SpringBoot?mybatis-plus使用json字段的相關(guān)資料,需要的朋友可以參考下2024-01-01