一文詳解SpringBoot如何切換Redis的DB
本文深入解析了Spring Redis動(dòng)態(tài)切換數(shù)據(jù)庫(kù)的核心機(jī)制,指出僅調(diào)用setDatabase()和resetConnection()無(wú)法真正切換數(shù)據(jù)庫(kù)的根本原因。關(guān)鍵在于必須調(diào)用afterPropertiesSet()方法,該方法會(huì)重新初始化連接工廠、重建連接池,使新的database配置完全生效。文章提供了生產(chǎn)可用的動(dòng)態(tài)切庫(kù)標(biāo)準(zhǔn)寫(xiě)法,并警告缺少這一步驟將導(dǎo)致數(shù)據(jù)錯(cuò)亂、連接池混亂等問(wèn)題。同時(shí)提醒避免頻繁切庫(kù)和并發(fā)操作,建議為每個(gè)DB單獨(dú)配置RedisTemplate。下面我們就來(lái)深入了解下吧
afterPropertiesSet() 深度解析
Spring Redis 動(dòng)態(tài)切換數(shù)據(jù)庫(kù)時(shí),真正讓切庫(kù)生效的關(guān)鍵:afterPropertiesSet() 深度解析
在使用 Spring Data Redis(Lettuce 客戶端)時(shí),許多開(kāi)發(fā)者會(huì)遇到一個(gè)經(jīng)典需求:在運(yùn)行期動(dòng)態(tài)切換 Redis 的 database(db index)。
常見(jiàn)的代碼類(lèi)似這樣:
LettuceConnectionFactory connectionFactory =
(LettuceConnectionFactory) redisTemplate.getConnectionFactory();
connectionFactory.setDatabase(num);
redisTemplate.setConnectionFactory(connectionFactory);
connectionFactory.resetConnection();
connectionFactory.afterPropertiesSet();
網(wǎng)上很多文章都告訴你:
- 調(diào)用
setDatabase(num)修改數(shù)據(jù)庫(kù) - 或者調(diào)用
resetConnection()重建連接
但實(shí)際運(yùn)行時(shí)你會(huì)發(fā)現(xiàn)一個(gè)反?,F(xiàn)象:
你明明把 database 切到 2,結(jié)果寫(xiě)的數(shù)據(jù)還是落到 DB 0。
原因是什么?關(guān)鍵就在于——真正讓切庫(kù)生效的是 afterPropertiesSet(),不是其它方法。
本文將從源碼、連接池行為、RedisTemplate 機(jī)制等方面,深入解析這個(gè)關(guān)鍵點(diǎn),并給出一套可直接投入生產(chǎn)的動(dòng)態(tài)切庫(kù)方案。
setDatabase() ≠ 切換數(shù)據(jù)庫(kù)
首先要明確一點(diǎn):
setDatabase() 只是修改了“屬性值”,絕不會(huì)影響已經(jīng)存在的連接池和連接。
為什么?
因?yàn)?LettuceConnectionFactory 內(nèi)部采用的是 長(zhǎng)連接池機(jī)制,連接是在 Bean 初始化完成后創(chuàng)建的,而不是在屬性變更時(shí)動(dòng)態(tài)調(diào)整。
所以:
- 你 setDatabase(2),連接池根本不會(huì)重建
- RedisTemplate 依舊復(fù)用舊連接
- Redis 命令仍然落在舊的 DB
這就是為什么 “setDatabase 看似成功,但其實(shí)沒(méi)生效”。
resetConnection() 也不夠,它只是“斷開(kāi)舊連接”
那 resetConnection() 能解決嗎?依然不行。
它的作用是:
- 關(guān)閉舊連接
- 清理當(dāng)前連接資源
但它 不會(huì)重新初始化連接池,也不會(huì)重新構(gòu)建 RedisURI、ClientOptions、PoolConfig 等底層配置。
簡(jiǎn)單說(shuō):
| 方法 | 做了什么 | 是否讓切庫(kù)生效 |
|---|---|---|
| setDatabase() | 改屬性 | ? 不生效 |
| resetConnection() | 關(guān)連接 | ? 不生效 |
| afterPropertiesSet() | 重新初始化連接工廠 + 重建連接池 | ??? 切庫(kù)真正生效 |
afterPropertiesSet() 才是“真正生效”的核心
afterPropertiesSet() 是 Spring Bean 初始化方法,會(huì)在容器啟動(dòng)時(shí)自動(dòng)觸發(fā)一次。
關(guān)鍵是:
當(dāng)你修改 connectionFactory 的配置后,必須再主動(dòng)調(diào)用一次 afterPropertiesSet(),才能讓新的配置真正用于構(gòu)建新的連接池。
它會(huì)做的事情包括:
- 重建 RedisURI(其中包含 database index)
- 重建 LettuceClientConfiguration
- 重建 NettyClientResources
- 重建連接池
- RedisTemplate 獲取的新連接全部指向新數(shù)據(jù)庫(kù)
所以:
afterPropertiesSet() 才是動(dòng)態(tài)切庫(kù)中唯一真正關(guān)鍵的步驟。
沒(méi)有它,其他方法都只能修改表面,看起來(lái)改了,實(shí)際上沒(méi)用。
動(dòng)態(tài)切庫(kù)的標(biāo)準(zhǔn)寫(xiě)法(生產(chǎn)可用)
public void switchDb(int num) {
LettuceConnectionFactory connectionFactory =
(LettuceConnectionFactory) redisTemplate.getConnectionFactory();
// 1. 修改數(shù)據(jù)庫(kù) index
connectionFactory.setDatabase(num);
// 2. 重新設(shè)置到 RedisTemplate(否則模板繼續(xù)持有舊連接工廠)
redisTemplate.setConnectionFactory(connectionFactory);
// 3. 清空舊連接
connectionFactory.resetConnection();
// 4. 最關(guān)鍵的一步:重新初始化連接工廠
connectionFactory.afterPropertiesSet();
}
沒(méi)調(diào)用 afterPropertiesSet() 將出現(xiàn)什么問(wèn)題?
假設(shè)你原來(lái)在 DB 0,切到 DB 2:
switchDb(2);
redisTemplate.opsForValue().set("test", "A");
如果缺少 afterPropertiesSet(),會(huì)出現(xiàn):
- 數(shù)據(jù)依然寫(xiě)入 DB 0
- RedisTemplate 仍持有舊連接
- 并發(fā)下連接池混亂,導(dǎo)致不可控 bug
- 緩存錯(cuò)亂,數(shù)據(jù)跨庫(kù)寫(xiě)入
許多開(kāi)發(fā)者踩坑正是因?yàn)槿鄙龠@一步。
深入到源碼(為什么 afterPropertiesSet 能生效?)
afterPropertiesSet() 最重要的操作是:
this.client = createClient(); this.connectionProvider = new LettuceConnectionProvider(client, redisURI); this.pool = createConnectionPool(redisURI, clientConfiguration);
完全重新構(gòu)建了:
- DefaultClientResources
- RedisURI(含新 database)
- StateAwareConnectionPool
- ConnectionProvider
這意味著:
原來(lái)的連接全部失效,新的連接全部基于新 database 構(gòu)建。
生產(chǎn)環(huán)境動(dòng)態(tài)切庫(kù)有哪些注意事項(xiàng)
別頻繁切庫(kù)
每次切庫(kù)都會(huì)重建連接池,開(kāi)銷(xiāo)很大。
多線程環(huán)境要避免并發(fā)切庫(kù)
同一套 RedisTemplate 不適合“多人同時(shí)改庫(kù)”,應(yīng)考慮:
- 每個(gè) DB 一個(gè) RedisTemplate
- 或者一個(gè)切庫(kù)請(qǐng)求只使用一次 RedisTemplate
結(jié)語(yǔ)
動(dòng)態(tài)切換 Redis 數(shù)據(jù)庫(kù)是一個(gè)看似簡(jiǎn)單但極易踩坑的操作。大多數(shù)錯(cuò)誤并不是代碼寫(xiě)錯(cuò),而是:
以為 setDatabase + resetConnection 就能切庫(kù),但沒(méi)有意識(shí)到 連接池需要重建。
核心原因只有一句話:
afterPropertiesSet() 才是真正讓 Redis 切庫(kù)生效的關(guān)鍵步驟,它重新構(gòu)建了所有連接資源。
到此這篇關(guān)于一文詳解SpringBoot如何切換Redis的DB的文章就介紹到這了,更多相關(guān)SpringBoot切換Redis DB內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot+Redis多DB動(dòng)態(tài)切換幾種方式總結(jié)
- SpringBoot整合redis及mongodb的詳細(xì)過(guò)程
- SpringBoot實(shí)現(xiàn)Redis多數(shù)據(jù)庫(kù)切換(多數(shù)據(jù)源配置)
- SpringBoot讀寫(xiě)Redis客戶端并實(shí)現(xiàn)Jedis技術(shù)切換功能
- SpringBoot結(jié)合Redis配置工具類(lèi)實(shí)現(xiàn)動(dòng)態(tài)切換庫(kù)
- springboot連接redis并動(dòng)態(tài)切換database的實(shí)現(xiàn)方法
相關(guān)文章
idea 實(shí)現(xiàn)git rebase操作應(yīng)用場(chǎng)景
本文結(jié)合idea工具進(jìn)行rebase的各種場(chǎng)景的操作,借助工具更能直觀地觀察到分支之間地操作差異,方便我們理解rebase的各種操作以及場(chǎng)景的使用,對(duì)idea git rebase操作知識(shí)感興趣的朋友一起看看吧2024-01-01
Java實(shí)現(xiàn)獲取小程序帶參二維碼并保存到本地
這篇文章主要介紹了Java實(shí)現(xiàn)獲取小程序帶參二維碼并保存到本地,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
Hadoop使用hdfs指令查看hdfs目錄的根目錄顯示被拒的原因及解決方案
這篇文章主要介紹了Hadoop使用hdfs指令查看hdfs目錄的根目錄顯示被拒的原因及解決方案,分布式部署hadoop,服務(wù)機(jī)只有namenode節(jié)點(diǎn),主機(jī)包含其他所有節(jié)點(diǎn),本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10
Java使用MethodHandle來(lái)替代反射,提高性能問(wèn)題
這篇文章主要介紹了Java使用MethodHandle來(lái)替代反射,提高性能問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-05-05
Java字符串?dāng)?shù)字左右補(bǔ)全0的四種方式
這篇文章主要給大家介紹了關(guān)于Java字符串?dāng)?shù)字左右補(bǔ)全0的四種方式,在編程中有時(shí)候我們需要對(duì)一個(gè)字符串進(jìn)行字符填充,以滿足某些特定的要求,其中補(bǔ)全0是一種常見(jiàn)的需求,需要的朋友可以參考下2023-08-08
詳解關(guān)于mybatis-plus中Service和Mapper的分析
這篇文章主要介紹了詳解關(guān)于mybatis-plus中Service和Mapper的分析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09

