[TOC]
1、問題場景及說明
系統中同時使用 Redis 緩存和 Guava本地緩存。用 Guava 緩存將 Redis 緩存包了一層。可以提升效率,但是也會引出一些問題。
問題:同一個本地緩存Map,獲取到的值有時會不一致。 不同機器可能不一致,同一機器也可能不一致。很神奇,但是數據庫里都是對的。
后來發現,因為有一個請求會對該緩存進行remove操作,導致緩存改變。 如果這個請求到某個機器上,該台機器上的緩存就會被修改。 同時緩存過期時間為一分鍾,過期之后獲取到的緩存是正常的。如果該台機器沒有再次接收到請求,那么緩存就正常;如果再次接收到,緩存就異常了。
2、Redis 緩存是深拷貝
從 Redis 中獲取緩存時,系統中的數據對象是 Redis 緩存的副本。 對該對象的任何操作都不會影響 Redis 中的緩存,后續再次獲取還是修改之前的數據。 除非執行Redis的更新操作。
3、Guava本地緩存直接獲取則是淺拷貝
以獲取一個MAP為例:如果直接從緩存中取,則是淺拷貝。 對緩存數據的任何操作都會同時修改緩存中的數據,下次從緩存中獲取則是修改之后的數據。
一般不會修改從緩存中獲取到的數據,但如果要修改,則需注意Redis和Guava的不同。
4、如何實現Guava獲取本地緩存是深拷貝?
**方法:**可將Guava的get方法封裝一層,將緩存中獲取到的數據包裝為一個新對象返回,以后直接使用封裝后的方法。
**注意:**這會影響Guava的性能,畢竟每次都需要構建一個新對象返回。
**建議:**本地緩存適合直接獲取的場景,沒必要包裝通用get方法。 如果要修改獲取到的數據,在修改的地方深拷貝一份操作即可。 即可利用Guava的優越性,又可實現需要修改數據的邏輯。 只是要注意,修改時不能直接操作原始對象,需操作深拷貝之后的對象。