在高併發場景下,肯定會發生這個問題,這裡簡單談談解決思路
1.常規簡單的解決方案
先刪除快取,在更新資料庫,如果刪除快取成功,修改資料庫失敗了,那麼資料庫中依然是舊資料,如果去讀取資料的時候,發現快取沒有,則去讀資料庫,資料庫會把舊資料載入到快取裡,這樣快取和資料庫則保持了一致。
2.如果在高併發的情況下會發生了如下更複雜的操作
比如有資料發生了變更,先刪除了快取,然後準備要去修改資料庫,此時還沒修改,這時候乙個請求過來,去讀快取,發現快取空了,去查詢資料庫,查到了修改前的舊資料,放到了快取中 ,之後資料變更的程式完成了資料庫的修改。完了,資料庫和快取中的資料不一樣了。。。
3.記憶體佇列
更新資料的時候,根據資料的唯一標識,將操作路由之後,傳送到乙個jvm內部的佇列中,讀取資料的時候,如果發現資料不在快取中,那麼將重新讀取資料+更新快取的操作,根據唯一標識路由之後,也傳送同乙個jvm內部的佇列中
乙個佇列對應乙個工作執行緒,每個工作執行緒序列拿到對應的操作,然後一條一條的執行。這樣的話,乙個資料變更的操作,先執行刪除快取,然後再去更新資料庫,但是還沒完成更新。此時如果乙個讀請求過來,讀到了空的快取,那麼可以先將快取更新的請求傳送到佇列中,此時會在佇列中積壓,然後同步等待快取更新完成
這裡有乙個優化點,乙個佇列中,其實多個更新快取請求串在一起是沒意義的,因此可以做過濾,如果發現佇列中已經有乙個更新快取的請求了,那麼就不用再放個更新請求操作進去了,直接等待前面的更新操作請求完成即可,待那個佇列對應的工作執行緒完成了上乙個操作的資料庫的修改之後,才會去執行下乙個操作,也就是快取更新的操作,此時會從資料庫中讀取最新的值,然後寫入快取中。如果請求還在等待時間範圍內,不斷輪詢發現可以取到值了,那麼就直接返回; 如果請求等待的時間
超過一定時長,那麼這一次直接從資料庫中讀取當前的舊值。
redis快取 資料庫雙寫不一致
讀的時候 先讀快取,快取沒有的話,再讀取資料庫,然後取出資料後放入快取,同時返回響應 更新的時候 先刪除快取,然後再更新資料庫 之所以刪除快取而不是更新,其實是乙個懶載入的思想,避免頻繁更新,降低開銷,同時也可以避免更新快取成功後在更新資料庫時異常帶來的問題 場景1 先修改資料庫,再修改 刪除快取,...
快取與資料庫雙寫不一致
在大併發下,多執行緒運算元據庫與快取會存在兩者資料不一致的問題。首先重要的是先更新資料庫,在失效快取。執行緒1先更新資料庫,將字段t改為6,然後將快取失效,執行緒結束。執行緒2過來讀資料庫,讀取到了t為6的資訊,在準備插入快取之前發生了執行緒排程,執行緒3過來更新資料庫,並且將快取失效後執行緒3結束...
高併發快取 資料庫雙寫不一致
情景一 先修改資料庫,再刪除快取,如果刪除快取失敗了,那麼會導致資料庫中是新資料,快取中是舊資料,資料出現不一致 解決方案 先刪除快取,再修改資料庫,如果刪除快取成功了,如果修改資料庫失敗了,那麼資料庫中是舊資料,快取中是空的,那麼資料不會不一致 因為讀的時候快取沒有,則讀資料庫中舊資料,然後更新到...