表數據過多時,一般會爲表的記錄增長緩存。在咱們的業務中,用戶的信息是使用redis來作緩存的,避免用戶的每次請求都直接查詢數據庫。
在一些場景下,須要爲用戶的一連串數據庫操做作事務管理,同時也須要刪除掉舊的用戶信息表的緩存。例如如今有一個金幣兌換物品的場景,用戶兌換的流程以下:html
- 用戶信息表:扣除用戶金幣
- 用戶的兌換表:新增一行記錄,狀態爲:「已扣金幣;未建立訂單」
- 用戶金幣流水錶:新增用戶扣除金幣記錄
- 進行實際下單兌換的接口調用
- 更新用戶兌換表狀態爲:已扣除金幣
若是在進行實際下單兌換時接口調用返回來非超時失敗,那麼須要將一、二、3步驟的數據庫操做進行回滾。
這種場景下,何時刪除舊的緩存就顯得很重要,更新緩存的時機不當,會留下緩存數據與數據庫數據不一致的隱患。例如將緩存刪除的操做位於如下位置時:redis
- 用戶信息表:扣除用戶金幣
--》 刪除用戶信息表緩存
- 用戶的兌換表:新增一行記錄,狀態爲:「已扣金幣;未建立訂單」
- 用戶金幣流水錶:新增用戶扣除金幣記錄
- 進行實際下單兌換的接口調用
- 更新用戶兌換表狀態爲:已扣除金幣
在併發的狀況下,可能會出現:數據庫
- 下單兌換的線程刪除了用戶信息表緩存
- 另外一個請求的線程從新讀取用戶信息表數據並更新了緩存
- 此時下單兌換的線程下單失敗進行了金幣回滾
此時緩存中的用戶金幣與數據庫表中的用戶金幣是不一致的。將緩存刪除的位置處於如下位置時:緩存
- 用戶信息表:扣除用戶金幣
- 用戶的兌換表:新增一行記錄,狀態爲:「已扣金幣;未建立訂單」
- 用戶金幣流水錶:新增用戶扣除金幣記錄
- 進行實際下單兌換的接口調用
- 更新用戶兌換表狀態爲:已扣除金幣
--》 刪除用戶信息表緩存
則不會發生以上的狀況。在使用表級緩存 + 數據庫事務 的環境下 須要注意這個問題。
同理的,在更新表級緩存的時候,在數據庫的數據成功更新後,再刪除緩存,纔是穩妥的操做。併發
原文:http://www.javashuo.com/article/p-vdoctzss-hg.html線程