1、如果Redis中有數據,需要和資料庫中的值相同。
2、如果Redis中無數據,資料庫中的最新值要對Redis進行同步更新。
寫入資料庫也同步寫Redis緩存,快取和資料庫中的資料一致;對於讀寫緩存來說,要確保快取和資料庫中的資料一致,就要確保同步直寫策略。
某些業務運作中,MySQL資料更新之後,允許在一定時間後再進行Redis資料同步,例如物流系統。
當出現異常情況時,必須將失敗的動作重新修補,需要藉助rabbitmq或kafka進行重寫。
多個執行緒同時去查詢資料庫的這條數據,那麼我們可以在第一個查詢資料的請求上使用一個互斥鎖來鎖住它。
其他的執行緒走到這一步拿不到鎖就等著,等第一個執行緒查詢到了數據,然後做快取。
後面的執行緒進來發現已經有快取了,就直接走快取。
public String get(String key){ // 从Redis缓存中读取 String value = redisTemplate.get(key); if(value != null){ return value; } synchronized (RedisTest.class){ // 重新尝试从Redis缓存中读取 value = redisTemplate.get(key); if(value != null){ return value; } // 从MySQL数据库中查询 value = studentDao.get(key); // 写入Redis缓存 redisTemplate.setnx(key,value,time); return value; } }
依照常理出牌的話,應該都是如此吧?那麼,這種情況下,會有啥問題呢?
如果更新資料庫成功後,更新Redis之前異常了,會出現什麼情況呢?
資料庫與Redis內快取資料不一致。
多執行緒情況下,會有問題。
例如
線程1更新redis = 200;
執行緒2更新redis = 100;
執行緒1更新完MySQL資料後,發現Redis中已經有資料了,之前都刪過了,那我就不更新了;
完蛋了。 。/** * 延时双删 * @autor 哪吒编程 */ public void deleteRedisData(Student stu){ // 删除Redis中的缓存数据 jedis.del(stu); // 更新MySQL数据库数据 studentDao.update(stu); // 休息两秒 try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } // 删除Redis中的缓存数据 jedis.del(stu); }
引入訊息中間件解決戰鬥,再一次詳細的複盤一下。
資料庫將操作資訊寫入binlog日誌;
訂閱程序提取出key和資料;
嘗試刪除快取操作,發現刪除失敗;
#########將這些資料資訊傳送到訊息中介軟體中; ############從訊息中間件取得該數據,重新操作;#############5、總結######哪吒推薦使用第四種方式,先更新資料庫,再刪除快取。 ######方式①和方式②缺點太過明顯,不考慮;###方式③中的sleep,總是讓人頭疼;###方式④是一個比較全面的方案,但是增加了學習成本、維護成本,因為增加了訊息中間件。 ######五、MySQL主從複製工作原理###############1、當master 主伺服器上的資料改變時,則將其變更寫入二進位事件在日誌檔案中;######2、salve 從伺服器會在一定時間間隔內對master 主伺服器上的二進位日誌進行探測,探測其是否發生過改變,######如果偵測到master 主伺服器的二進位事件日誌發生了改變,則開始一個I/O Thread 請求master 二進位事件日誌;######3、同時master 主伺服器為每個I/O Thread 啟動一個dump Thread,用於向其傳送二進位事件日誌;######4、slave 從伺服器將接收到的二進位事件日誌儲存到自己本機的中繼日誌檔案;###5、salve 從伺服器將啟動SQL Thread 從中繼日誌中讀取二進位日誌,在本機重播,使得其資料和主伺服器保持一致;
##6、最後I/O Thread 和SQL Thread 將進入睡眠狀態,等待下一次被喚醒。以上是MySQL資料庫和Redis快取一致性的更新策略是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!