什么是臟數據,緩存中是否可能產生臟數據,如果出現臟數據該怎么處理?


(1)背景介紹:

臟數據:從目標中取出的數據已經過期、錯誤或者沒有意義,這種數據就叫做臟數據。

臟讀:讀取出來臟數據就叫臟讀。

 

(2)知識剖析:
1、數據庫中的並發事務處理問題:

臟讀:在並發訪問的情況下,不同的事務對相同的數據進行操作,在事務A修改數據還未提交的時候,事務B對該數據進行讀取,讀出了事物A修改過后的數據,但是事物A最終沒有提交,這種情況就是數據庫中的臟讀情況

更新丟失:對於同一行數據不同事務進行更新,結果覆蓋

幻讀:事務A前后兩次讀取,后一次讀取的數據變多了,事物B在兩次讀取中間已經進行數據插入

不可重復讀:事務A讀取了事務B修改前后的兩次數據,不符合隔離型

隔離等級:可以解決上述問題,mysql默認可重復讀的隔離等級,只會存在讀取的數據和數據庫不一致的問題

2、mybati一級緩存中的臟數據:

mybatis的一級緩存:默認是SqlSession級別,只要通過session查過的數據,都會放在session上,下一次再查詢相同id的數據,都直接沖緩存中取出來,而不用到數據庫里去取了。

mybatis一級緩存臟數據:當有不同的sqlSession在對數據庫進行操作,一級緩存只能保證當前sqlSession中的增刪改在一級緩存中自動更新,就會產生臟數據。

3、mybati二級緩存中的臟數據:

mybatis二級緩存:是SessionFactory級別,和namespace綁定,同一個namespace放到一個緩存對象中,當這個namaspace中執行了非sselect語句的時候,整個namespace中的緩存全部清除掉。

 

mybatis二級緩存臟數據:引起臟讀的操作通常發生在多表關聯操作中,比如在兩個不同的mapper中都涉及到同一個表的增刪改查操作,當其中一個mapper對這張表進行查詢操作,此時另一個mapper進行了更新操作刷新緩存,然后第一個mapper又查詢了一次,那么這次查詢出的數據是臟數據。出現臟讀的原因是他們的操作的緩存並不是同一個。

 

所以不推薦使用mybatis的自帶一二級緩存,推薦使用第三方緩存:memcached或者redis。

 

(3)常見問題:
redis中怎么更新緩存避免臟讀?

 

(4)解決方案:
讀寫部分:

if(redis存在數據){
讀取redis數據

}else{
數據庫讀取,同時存redis+設置超時時間

 

更新部分:

if(數據庫update){
更新redis+設置超時時間

 

(5)編碼實戰:
演示讀寫部分和更新部分

 

(6)拓展思考:
還有哪些其他方式進行redis數據更新

1、主動更新:后台點擊更新緩存按鈕,從DB查找最新數據集合,刪除原緩存數據,存儲新數據到緩存(或者用定時任務來做)

問題:更新過程中刪除掉緩存后剛好有業務在查詢,那么這個時候返回的數據會是空,會影響用戶體驗,如果高並發穿透DB,可能導致服務器崩潰

2、由用戶觸發更新:前台獲取數據時發現沒有緩存數據就會去數據庫同步數據到緩存

問題:當並發請求獲取緩存數據不存在的時候,就會產生並發的查詢數據的操作

 

3、提前加載好數據:后台點擊更新緩存按鈕,從DB查找最新數據集合,這里不刪除緩存,通過遍歷數據覆蓋和刪除掉無效的數據

問題:邏輯相對麻煩,而且更新機制無法通用

 

(7)參考文獻:
百度谷歌

 

(8)更多討論:
Q1:數據庫臟數據和redis臟數據的區別?

A1:數據庫臟數據是用戶對數據進行操作存儲,存儲的數據和實際不符合,redis臟數據是相對於數據庫數據而言的,redis的數據和數據庫中數據不一致就會導致臟數據
Q2:文中代碼實戰中的redis更新方式有什么缺點?

A2:缺點:增加的判斷的方法,效率偏低,當並發量高時,效率影響會更大
Q3:主動更新方式進行redis更新怎么實現?
A3:在后台管理中,設置一個按鈕,更新redis的操作,一般在晚上用戶訪問量少的時候,數據從數據庫中查出后放入redis

 

先備份數據庫 create table ApiParamInfo2022_04_27  as SELECT  *  from NFSDB_ZJS.ApiParamInfo

再找兩張表不一樣的數據 再刪除數據

delete a FROM NFSDB_ZJS.ApiParamInfo a LEFT JOIN NFSDB.ApiParamInfo b ON a.id=b.id WHERE b.id IS NULL

select a.* from NFSDB.ApiParamInfo a left join NFSDB_ZJS.ApiParamInfo b on a.id=b.id where b.id is null -- 1849

SELECT COUNT (*) FROM NFSDB.ApiInfo -- 19119
SELECT COUNT (*) FROM NFSDB.ApiParamInfo -- 19119 64949
SELECT COUNT (*) FROM NFSDB_ZJS.ApiInfo -- 17301 17270
SELECT COUNT (*) FROM NFSDB_ZJS.ApiParamInfo -- 17301 17270 58374

insert into NFSDB_ZJS.ApiParamInfo select a.* from NFSDB.ApiParamInfo a left join NFSDB_ZJS.ApiParamInfo b on a.id=b.id where b.id is null


SELECT a.* FROM NFSDB_ZJS.ApiParamInfo a LEFT JOIN NFSDB.ApiParamInfo b ON a.id=b.id WHERE b.id IS NULL


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM