Redis學習二

Redis和數據庫數據一致性問題

Redis作為緩存分兩種情形

  1. 只讀緩存, 只讀緩存無需考慮數據更新問題, Redis中有則返回Redis中的數據, Redis無則查詢數據庫
  2. 讀寫緩存
    • 同步直寫策略
    • 異步緩寫策略

數據讀取流程:

正常回寫Redis代碼流程:

public Object getDataById(String id) {// 1. 先去Redis中查詢Object obj;obj = redisTemplate.opsForValue().get(DATA_PR + id);if (obj == null) {// 2. redis中查詢出來為null則查詢數據庫obj = testMapper.getDataById(id);if (obj == null) {// 3.1redis, 數據庫都沒有數據// 可以給這個id給個空值存在Redis中redisTemplate.opsForValue().set(DATA_PR + id, "null");} else {// 3.2 數據庫中有數據將數據寫回RedisredisTemplate.opsForValue().set(DATA_PR + id, obj);}}return obj;}

保證并發時, 避免同一數據頻繁寫入Redis對回寫緩存代碼進行加鎖

public Object getDataById1(String id) {// 1. 先去Redis中查詢Object obj;obj = redisTemplate.opsForValue().get(DATA_PR + id);if (obj == null) {// 緩存不存在則加鎖// 假設請求量很大synchronized (TestServiceImpl.class) {obj = redisTemplate.opsForValue().get(DATA_PR + id);if (obj != null) {// 查詢有數據則直接返回return obj;} else {// 沒有數據再查詢數據庫obj = testMapper.getDataById(id);// 回寫緩存if (obj != null) {redisTemplate.opsForValue().setIfAbsent(DATA_PR + id, obj, 20, TimeUnit.SECONDS);return obj;} else {return null;}}}}return obj;}

給緩存設置過期時間, 定期清理緩存并回寫, 是保證最終一致性的解決方案

我們可以對存入緩存的數據設置過期時間, 所有的寫操作以數據庫為準, 對緩存的操作只是盡最大努力即可, 也就是說數據庫寫成功緩存更新失敗, 那么只要達到過期時間, 則后面的讀請求自然會從數據庫讀取新值然后回填緩存,達到一致性, 要以數據庫寫入庫為準

更新數據庫并更新Redis有以下幾種情況

  1. 先更新數據庫再更新Redis

    這種情況會出現的問題:

    請求A先將字段x更新為10

    請求B后將字段x更新為20

    正常流程:

    請求A更新數據庫將x更新為10

    請求A更新Redis 將x更新為10

    請求B更新數據庫將x更新為20

    請求B更新Redis 將x更新為20

    異常情況:

    請求A更新數據庫將x更新為10

    請求B更新數據庫將x更新為20

    請求B更新Redis 將x更新為20

    請求A更新Redis 將x更新為10

    此時數據庫x為10, Redis中x為20出現緩存和數據庫數據不一致情況

  2. 先更新Redis再更新數據庫

    這種情況會出現的問題:

    請求A先將字段x更新為10

    請求B后將字段x更新為20

    正常流程:

    請求A更新Redis 將x更新為10

    請求A更新數據庫將x更新為10

    請求B更新Redis將x更新為20

    請求B更新數據庫將x更新為20

    異常情況:

    請求A更新Redis 將x更新為10

    請求B更新Redis將x更新為20

    請求B更新數據庫將x更新為20

    請求A更新數據庫將x更新為10

    此時數據中為20, Redis中為10 出現緩存和數據庫數據不一致情況

  3. 先刪除Redis再更新數據庫

    這種情況會出現的問題:

    請求A先將字段x更新為10

    請求B查詢x的值

    正常流程

    請求A刪除Redis中x的值

    請求A更新數據中的值為10

    請求B查詢Redis中沒有值, 查詢數據庫

    請求B回寫緩存x的值

    異常流程

    請求A刪除Redis中x的值

    請求B查詢Redis中沒有值, 查詢數據庫但是此時請求A還未更新數據庫或者是還沒有commit

    請求B查詢數據庫, 回寫緩存

    請求A更新數據庫

    此時緩存中仍然是緩存的舊值, 數據庫和緩存值不一致

  4. 先更新數據庫再刪除Redis

    這種情況會出現的問題:

    請求A先將字段x更新為10

    請求B查詢x的值

    正常流程

    請求A更新數據庫

    請求A刪除Redis中的緩存值

    請求B查詢數據庫并回寫緩存

    異常流程

    請求A更新數據庫但未提交

    請求B讀取的是舊值

    請求A刪除緩存

為了解決先刪除后修改數據庫的異常情況

延時雙刪

public void updateData(Object obj, String id) {// 先刪除緩存中的數據redisTemplate.opsForValue().getAndDelete(DATA_PR + id);// 再更新數據庫testMapper.updateData(obj);// 再次刪除緩存中的數據避免其他線程讀取舊值并回寫緩存// 需要在這里等待,等待的原因是如果另外的線程讀取的線程還在回寫的流程中舊值還未寫到緩存中, 那么刪除是沒有意義的// 這里等待的時間就是大于等待其他線程將舊值寫入緩存的時間try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {throw new RuntimeException(e);}redisTemplate.opsForValue().getAndDelete(DATA_PR + id);}

通常我們會采用先更新數據庫再刪除Redis緩存, 但是依然會存在在更新期間讀取到舊值的情況, 還會存在刪除緩存失敗問題, 此時可引入消息中間件將需要更改的數據推送到MQ, 再通過MQ去對Redis進行刪除, 這樣也不能保證強一致性, 只是一個比較折中的方案

引入中間件自動同步數據到Redis canal

如果我們的數據庫事MySQL可以通過引入開源中間件canal對MySQL的binlog進行監聽, 當數據庫表發生變化時自動去將MySQL的變更寫到我們的緩存中

未完待續…

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/73767.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/73767.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/73767.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

深入理解 Linux 文件權限:從 ACL 到擴展屬性,解剖底層技術細節與命令應用

Linux 以其強大而精密的文件權限和屬性管理機制著稱,這一體系不僅是系統安全的關鍵基石,還為靈活性和擴展性提供了堅實支撐。從傳統的九位權限模型到訪問控制列表(ACL)、擴展文件屬性(Extended Attributes)…

劍指Offer35- - 鏈表

1. 題目描述 這題題意感覺說的不是很清楚,容易讓人產生歧義!其實題意很簡單,給你一個鏈表 head,你深拷貝它,然后返回即可,注意不能修改原鏈表 /* // Definition for a Node. class Node { public:int val;N…

C 語言常用關鍵字詳解:static、const、volatile

C 語言常用關鍵字詳解:static、const、volatile 文章目錄 C 語言常用關鍵字詳解:static、const、volatile1. static 關鍵字1.1 用于局部變量示例: 1.2 用于全局變量示例: 1.3 用于函數示例: 2. const 關鍵字2.1 用于局…

Centos7本地部署阿里Qwen2-7B模型

1.從hagging face下載模型 2.把下載的模型文件,放到/usr/local/Qwen2-7B目錄下 3.創建虛擬環境,安裝依賴 1.環境安裝 sudo yum update -y sudo yum install -y python3 python3-pip git 2.創建虛擬環境并激活 python3 -m venv qwen2_env source qwen2_…

群暉監控套件通過ONVIF協議添加海康攝像頭

1. 首先登錄錄像機 通道管理 找到每個攝像頭的IP地址 2. 登錄某個攝像頭 配置 3. 添加用戶名(注意不能是admin) 設置賬戶密碼 用戶類型選管理員 4. 群暉里面添加攝像頭,自動搜索,添加剛剛那個IP的攝像頭 5. 驗證…

【C++】 —— 筆試刷題day_8

一、求最小公倍數 題目解析 題目很簡單,給定兩個數a和b求它們的最小公倍數。 算法思路 對于求兩個數的最小公倍數問題,想必已經非常熟悉了; 在之前學校上課時,記得老師提起過,最小公倍數 兩個數的乘積 除以最大公約數…

MTK Android12-Android13 設置系統默認語言

Android 系統,默認語言 文章目錄 需求:場景 參考資料實現方案實現思路編譯腳本熟悉-平臺熟悉mssi_64_cnkernel-4.19 解決方案修改文件-實現方案 源碼分析PRODUCT_LOCALES 引用PRODUCT_DEFAULT_LOCALE 定義get-default-product-locale 方法定義PRODUCT_DE…

系統如何查找文件?inode號又是什么?

下面分別詳細解釋您提到的三個問題: “文件系統怎么定位文件”、“inode 是什么”、“為什么刪除后還可能被占用”。 一、文件系統怎么定位文件 1.1 目錄與文件名并不直接存儲文件數據 在常見的 Unix/Linux 文件系統(如 ext4、xfs)或類似的…

05-SpringBoot3入門-整合SpringMVC(配置靜態資源、攔截器)

1、說明 在01-SpringBoot3入門-第一個項目-CSDN博客中,其實就已經整合了SpringMVC。下面講解怎么配置靜態資源和攔截器 2、配置靜態資源 命名:static(文件夾) 位置:src/main/resources 編寫一個html文件 訪問 http:/…

Transformer-LSTM、Transformer、CNN-LSTM、LSTM、CNN五模型多變量回歸預測

聚劃算!Transformer-LSTM、Transformer、CNN-LSTM、LSTM、CNN五模型多變量回歸預測 目錄 聚劃算!Transformer-LSTM、Transformer、CNN-LSTM、LSTM、CNN五模型多變量回歸預測預測效果基本介紹程序設計參考資料 預測效果 基本介紹 聚劃算!Tran…

樹莓派瀏覽器配置全解析:從輕量系統到網頁應用平臺

樹莓派(Raspberry Pi)不僅是嵌入式開發的入門利器,也因其低成本和強大的社區支持而成為物聯網、數字標牌、教育培訓等領域的熱門平臺。在很多應用中,運行一個瀏覽器并作為 Web 前端展示、操作或交互的能力顯得尤為關鍵。 但在資源…

初識Qt(一)

本文部分ppt、視頻截圖原鏈接:萌馬工作室的個人空間-萌馬工作室個人主頁-嗶哩嗶哩視頻 1. Qt是什么? Qt是一個跨平臺的C應用程序開發框架,它既為圖形用戶界面(GUI)程序開發提供了強大支持,也能用于開發非GUI的控制臺程序、服務端…

六十天前端強化訓練之第三十二天之Babel 轉譯配置大師級深度講解

歡迎來到編程星辰海的博客講解 看完可以給一個免費的三連嗎,謝謝大佬! 目錄 一、核心概念與知識體系詳解 1. Babel 工作原理全景解析 二、完整配置方案(帶詳細注釋) 1. 進階版 .babelrc 配置 2. Webpack 集成配置&#xff08…

智能提示詞生成器:助力測試工程師快速設計高質量測試用例

在軟件測試中,測試用例設計方法的選擇和實施是確保軟件質量的重要步驟。測試工程師經常需要根據不同的測試場景、參數維度和業務需求,設計出覆蓋率高且有效的測試用例。然而,設計測試用例并非易事,特別是在面對復雜的業務邏輯時。 為了幫助測試工程師高效生成測試用例提示…

beanie.exceptions.CollectionWasNotInitialized

遇到這樣的情況不要慌,不要慌 1:檢查模型是否已經初始化: class TaskModel(Document):"""定時任務模型"""task_id: str Field(default_factorylambda: str(uuid.uuid4()), # 新增默認值description"任…

【CVE-2025-30208】| Vite-漏洞分析與復現

漏洞簡介 CVE-2025-30208 是 Vite 開發服務器中的一個任意文件讀取漏洞。該漏洞允許攻擊者通過特定的 URL 參數繞過訪問控制,從而讀取服務器上的敏感文件(如 /etc/passwd 或 C:\windows\win.ini)。 該漏洞主要影響以下版本的 Vite&#xff…

將 Markdown 表格結構轉換為Excel 文件

在數據管理和文檔編寫過程中,我們經常使用 Markdown 來記錄表格數據。然而,Markdown 格式的表格在實際應用中不如 Excel 方便,特別是需要進一步處理數據時。因此,我們開發了一個使用 wxPython 的 GUI 工具,將 Markdown…

Golang使用 ip2region 查詢IP的地區信息

利用 ip2region 進行 IP 地址定位 import ("fmt""log""github.com/lionsoul2014/ip2region/binding/golang/xdb" )func main() {ip : "213.118.179.98"dbPath : ".\\cmd\\ip\\ip2region.xdb"// 1、初始化查詢器//searcher,…

對匿名認證的理解

概述:在 Spring Security 中,** 匿名認證(Anonymous Authentication)** 是一種特殊的認證機制,用于處理未提供有效憑證的請求。 匿名認證的本質 目的:允許未認證用戶訪問特定資源。原理: 當請求…

C++調用Python

Python安裝 地址: python官網 可以根據需要下載對應的版本。 調用python python測試腳本 # my_script.py import sys import jsondef calculate(a, b):return a * b 10 # 示例計算邏輯if __name__ "__main__":# 從命令行參數讀取 JSON 字符串try…