關于Redis快取資料一致性的問題,在網上看了一些解決方案,但是有些具體的一些執行細節一直不太明白,比如說先更新快取再異步更新資料庫這個方法,我理解的快取是基于方法的,也就是說一個查詢方法會在redis里面有一條快取資料(以key-value的方式存盤),如果先更新快取的話,如何在redis中定位到想要更新的資料呢?
打個比方:UserMapper里面有兩個查詢方法A、B和一個更新方法C,方法A、B的查詢結果里面都有id=1的資料,這時候快取里面就保存的有兩個key,value都有id=1的資料,如果執行C方法更新id=1的資料,按照先更新快取的方案,是如何定位到redis中的兩個key呢?如果找到了又是如何做更新的呢?如果在其他mapper中有多表查詢同樣用到了id=1的資料,又是如何定位到并且修改的呢?求大佬賜教!
uj5u.com熱心網友回復:
你確定可以將多個相同的key存盤在同一個redis中?你存成功了?
uj5u.com熱心網友回復:
不是同一個key,我保存的key值是方法的名+引數+引數中的屬性。value為方法的回傳結果。uj5u.com熱心網友回復:
redis資料重繪 常用的就是兩種解決方案啊,一個是延時雙刪一個是使用阿里的canal進行資料同步,無論是先刪快取在更新資料庫還是先更新資料庫在更新快取,再高并發下都會存在一定問題....雖然我沒有特別明白你上邊說的那種場景。uj5u.com熱心網友回復:
就是因為有高并發的問題,所以肯定有更好的解決方法呀,之前在網上看到一篇說是可以先更新快取,然后再異步的更新資料庫,所以具體的實作細節一頭霧水。uj5u.com熱心網友回復:
key 這樣定義 ,應該就有規則了User:id=1:selectUser
User:id=2:selectUser
User:id=1:findUser
User:id=2:findUser
洗掉 id=1 user 時,keys User:id=1 的都可以清除了
uj5u.com熱心網友回復:
那如果是修改id=1的資料?是把他的value拿出來修改完再放回去嗎?而且如果是一個集合的話是不是就要保存很多個id作為key?再假設修改的時候不是以id做條件怎么辦呢?比如where name=xxx。我先把問題說簡單點吧,如果是直接洗掉快取再操作資料庫,假如新增一條user資料,不可能將redis中的所有快取都洗掉吧,有些可能只用到了user表的某一個欄位,那么是如何定位到這些快取的key呢?uj5u.com熱心網友回復:
快取本就不適合 不固定 資料,你 要實時同步,資料修改就必須更新, 按你說的 查詢 結果 是不適合快取的,比如:查詢條件多,結果任意,快取就沒有意義了,每個快取并沒有很高的命中率。uj5u.com熱心網友回復:
資料修改是必須更新,問題是更新完資料之后怎樣才能準確的定位到與修改的資料有關的那些快取呢?是key用什么樣的格式存盤?還是value用什么樣的資料結構?uj5u.com熱心網友回復:
1、其實你所說的兩個id,在redis中應該是兩個不同的key,比如aaaId=1,和bbbId=1。至于aaa和bbb代表是什么意思,那就需要根據你的業務去定義了。2、更新redis的時候,比如更新key=aaaId的值,直接覆寫key=aaaId就行了。就跟map更新是一樣一樣的。
3、大的方向,redis是記憶體資料庫,獨立行程;map是java的資料型別
4、redis支持五種資料型別:string,list,hash(字典),set(集合),zset(有序集合)。java map和redis的hash對應,當然各自包含的方法不同
5、redis可以做主存,也可做快取。
uj5u.com熱心網友回復:
你的意思就是說保存的時候不能以方法為單位,要以資料庫的一條資料為單位是嗎?如果有一個查詢全部user的方法,資料庫里有100條redis中就得快取100個userId的key嗎?那這樣的話按其他條件查詢是不是又得快取100個呢?比如deleted=0的有100個。還有就是多表查詢要怎么快取呢?比如說現在有個方法A查詢所有的學生資訊和username(用的left join 只用到了user表的name欄位,回傳學生DTO),快取的結果為100個學生name和username,現在呼叫新增user的方法B,新增成功了,按道理A方法的快取也應該洗掉,因為A方法目的是查詢全部的學生資訊和username快取中是100username個現在變成了101username個,那么根據什么定位到這個A方法的key呢?
uj5u.com熱心網友回復:
不是的,你想象一下Map能存什么,redis就可以存什么。redis的key只能是普通資料型別,但是值可以是任意物件的json格式字串。取的時候把值轉換為你想要的物件再去處理就行了。
uj5u.com熱心網友回復:
1、其實你所說的兩個id,在redis中應該是兩個不同的key,比如aaaId=1,和bbbId=1。至于aaa和bbb代表是什么意思,那就需要根據你的業務去定義了。
2、更新redis的時候,比如更新key=aaaId的值,直接覆寫key=aaaId就行了。就跟map更新是一樣一樣的。
3、大的方向,redis是記憶體資料庫,獨立行程;map是java的資料型別
4、redis支持五種資料型別:string,list,hash(字典),set(集合),zset(有序集合)。java map和redis的hash對應,當然各自包含的方法不同
5、redis可以做主存,也可做快取。
你的意思就是說保存的時候不能以方法為單位,要以資料庫的一條資料為單位是嗎?如果有一個查詢全部user的方法,資料庫里有100條redis中就得快取100個userId的key嗎?那這樣的話按其他條件查詢是不是又得快取100個呢?比如deleted=0的有100個。還有就是多表查詢要怎么快取呢?比如說現在有個方法A查詢所有的學生資訊和username(用的left join 只用到了user表的name欄位,回傳學生DTO),快取的結果為100個學生name和username,現在呼叫新增user的方法B,新增成功了,按道理A方法的快取也應該洗掉,因為A方法目的是查詢全部的學生資訊和username快取中是100username個現在變成了101username個,那么根據什么定位到這個A方法的key呢?
不是的,你想象一下Map能存什么,redis就可以存什么。redis的key只能是普通資料型別,但是值可以是任意物件的json格式字串。取的時候把值轉換為你想要的物件再去處理就行了。
所以具體key要怎么存呢?我現在的問題不是說拿不到物件,我是想問如何通過key找到和修改的表相關的所有快取,因為修改過后的表的快取都應該刪掉,這樣才能保證資料一致性嘛,怎么才能找到這樣快取的key并且全部洗掉呢?
uj5u.com熱心網友回復:
1、其實你所說的兩個id,在redis中應該是兩個不同的key,比如aaaId=1,和bbbId=1。至于aaa和bbb代表是什么意思,那就需要根據你的業務去定義了。
2、更新redis的時候,比如更新key=aaaId的值,直接覆寫key=aaaId就行了。就跟map更新是一樣一樣的。
3、大的方向,redis是記憶體資料庫,獨立行程;map是java的資料型別
4、redis支持五種資料型別:string,list,hash(字典),set(集合),zset(有序集合)。java map和redis的hash對應,當然各自包含的方法不同
5、redis可以做主存,也可做快取。
你的意思就是說保存的時候不能以方法為單位,要以資料庫的一條資料為單位是嗎?如果有一個查詢全部user的方法,資料庫里有100條redis中就得快取100個userId的key嗎?那這樣的話按其他條件查詢是不是又得快取100個呢?比如deleted=0的有100個。還有就是多表查詢要怎么快取呢?比如說現在有個方法A查詢所有的學生資訊和username(用的left join 只用到了user表的name欄位,回傳學生DTO),快取的結果為100個學生name和username,現在呼叫新增user的方法B,新增成功了,按道理A方法的快取也應該洗掉,因為A方法目的是查詢全部的學生資訊和username快取中是100username個現在變成了101username個,那么根據什么定位到這個A方法的key呢?
不是的,你想象一下Map能存什么,redis就可以存什么。redis的key只能是普通資料型別,但是值可以是任意物件的json格式字串。取的時候把值轉換為你想要的物件再去處理就行了。
所以具體key要怎么存呢?我現在的問題不是說拿不到物件,我是想問如何通過key找到和修改的表相關的所有快取,因為修改過后的表的快取都應該刪掉,這樣才能保證資料一致性嘛,怎么才能找到這樣快取的key并且全部洗掉呢?
這個看你具體的業務了,比如你有一個用戶user表,一個成績score表,兩個都有一個主鍵id,你存到redis中的key就可以是userId、scoreId。
uj5u.com熱心網友回復:
redis 的使用,一般是有兩種觀念出現的。一種是把 redis 作為臨時存放資料的工具,所以,里面的資料一般都有一個存放時限,超時會自動洗掉,并且,這種觀念當中,資料庫的資料是處于核心地位的,也就是說,資料的更新操作,要優先更新資料庫,之后是重繪快取。
另一種是把 redis 當做記憶體型資料庫來使用,這種觀念中,redis 是資料庫,他里面存盤的東西可不是什么查詢結果的快取,就是活生生的資料。這也就是面試的時候,經常問到的,你了解key-value型資料庫嗎,巴拉巴拉的內容。
現在造成樓主理解困難的原因,就出現在,樓主想用第二種理念來處理第一種方式存放的資料,從根源上就會有極大的沖突。
換句話說,樓主理解的redis的用法,適用于先更新資料庫,再重繪快取的這種路數,即使將所有快取都清空,也不會造成資料不一致的問題。
那么,先更新快取,后更新資料庫的這種方案,他適用的場景,要求,key的編碼規則,就是資料庫里面的pk,至于怎么完成復雜查詢,這就要在設計的時候,想想辦法了。沒有想到,只能說明我們的見識還不夠多。
uj5u.com熱心網友回復:
相同的key會被覆寫的,不同的id加不同的前綴就好了,比如:redis_user_id = 1,redis_book_id = 1uj5u.com熱心網友回復:
好強。。。。。uj5u.com熱心網友回復:
還是你明白我的意思了,我也大概知道你給的解答了,多謝啦!uj5u.com熱心網友回復:
1、其實你所說的兩個id,在redis中應該是兩個不同的key,比如aaaId=1,和bbbId=1。至于aaa和bbb代表是什么意思,那就需要根據你的業務去定義了。
2、更新redis的時候,比如更新key=aaaId的值,直接覆寫key=aaaId就行了。就跟map更新是一樣一樣的。
3、大的方向,redis是記憶體資料庫,獨立行程;map是java的資料型別
4、redis支持五種資料型別:string,list,hash(字典),set(集合),zset(有序集合)。java map和redis的hash對應,當然各自包含的方法不同
5、redis可以做主存,也可做快取。
你的意思就是說保存的時候不能以方法為單位,要以資料庫的一條資料為單位是嗎?如果有一個查詢全部user的方法,資料庫里有100條redis中就得快取100個userId的key嗎?那這樣的話按其他條件查詢是不是又得快取100個呢?比如deleted=0的有100個。還有就是多表查詢要怎么快取呢?比如說現在有個方法A查詢所有的學生資訊和username(用的left join 只用到了user表的name欄位,回傳學生DTO),快取的結果為100個學生name和username,現在呼叫新增user的方法B,新增成功了,按道理A方法的快取也應該洗掉,因為A方法目的是查詢全部的學生資訊和username快取中是100username個現在變成了101username個,那么根據什么定位到這個A方法的key呢?
不是的,你想象一下Map能存什么,redis就可以存什么。redis的key只能是普通資料型別,但是值可以是任意物件的json格式字串。取的時候把值轉換為你想要的物件再去處理就行了。
所以具體key要怎么存呢?我現在的問題不是說拿不到物件,我是想問如何通過key找到和修改的表相關的所有快取,因為修改過后的表的快取都應該刪掉,這樣才能保證資料一致性嘛,怎么才能找到這樣快取的key并且全部洗掉呢?
這個看你具體的業務了,比如你有一個用戶user表,一個成績score表,兩個都有一個主鍵id,你存到redis中的key就可以是userId、scoreId。
那如果有個成績表的查詢方法只用到了user表的name并沒有用到id的話key不就保存不了user表的id了,那這種情況的話更新了user表也要刪這個方法的快取,怎么定位到這個快取的key呢?
uj5u.com熱心網友回復:
redis 的使用,一般是有兩種觀念出現的。
一種是把 redis 作為臨時存放資料的工具,所以,里面的資料一般都有一個存放時限,超時會自動洗掉,并且,這種觀念當中,資料庫的資料是處于核心地位的,也就是說,資料的更新操作,要優先更新資料庫,之后是重繪快取。
另一種是把 redis 當做記憶體型資料庫來使用,這種觀念中,redis 是資料庫,他里面存盤的東西可不是什么查詢結果的快取,就是活生生的資料。這也就是面試的時候,經常問到的,你了解key-value型資料庫嗎,巴拉巴拉的內容。
現在造成樓主理解困難的原因,就出現在,樓主想用第二種理念來處理第一種方式存放的資料,從根源上就會有極大的沖突。
換句話說,樓主理解的redis的用法,適用于先更新資料庫,再重繪快取的這種路數,即使將所有快取都清空,也不會造成資料不一致的問題。
那么,先更新快取,后更新資料庫的這種方案,他適用的場景,要求,key的編碼規則,就是資料庫里面的pk,至于怎么完成復雜查詢,這就要在設計的時候,想想辦法了。沒有想到,只能說明我們的見識還不夠多。
還是你明白我的意思了,我也大概知道你給的解答了,多謝啦!
uj5u.com熱心網友回復:
1、其實你所說的兩個id,在redis中應該是兩個不同的key,比如aaaId=1,和bbbId=1。至于aaa和bbb代表是什么意思,那就需要根據你的業務去定義了。
2、更新redis的時候,比如更新key=aaaId的值,直接覆寫key=aaaId就行了。就跟map更新是一樣一樣的。
3、大的方向,redis是記憶體資料庫,獨立行程;map是java的資料型別
4、redis支持五種資料型別:string,list,hash(字典),set(集合),zset(有序集合)。java map和redis的hash對應,當然各自包含的方法不同
5、redis可以做主存,也可做快取。
你的意思就是說保存的時候不能以方法為單位,要以資料庫的一條資料為單位是嗎?如果有一個查詢全部user的方法,資料庫里有100條redis中就得快取100個userId的key嗎?那這樣的話按其他條件查詢是不是又得快取100個呢?比如deleted=0的有100個。還有就是多表查詢要怎么快取呢?比如說現在有個方法A查詢所有的學生資訊和username(用的left join 只用到了user表的name欄位,回傳學生DTO),快取的結果為100個學生name和username,現在呼叫新增user的方法B,新增成功了,按道理A方法的快取也應該洗掉,因為A方法目的是查詢全部的學生資訊和username快取中是100username個現在變成了101username個,那么根據什么定位到這個A方法的key呢?
不是的,你想象一下Map能存什么,redis就可以存什么。redis的key只能是普通資料型別,但是值可以是任意物件的json格式字串。取的時候把值轉換為你想要的物件再去處理就行了。
所以具體key要怎么存呢?我現在的問題不是說拿不到物件,我是想問如何通過key找到和修改的表相關的所有快取,因為修改過后的表的快取都應該刪掉,這樣才能保證資料一致性嘛,怎么才能找到這樣快取的key并且全部洗掉呢?
有個辦法 加版本號唄。
每次讀取最新加載最新版本號
舊的版本號定期清理掉
uj5u.com熱心網友回復:
加版本號也得定位到這個方法的key呀,不然所以key的版本號都變了不就是所有快取都失效了,那就快取雪崩啦uj5u.com熱心網友回復:
加版本號也得定位到這個方法的key呀,不然所以key的版本號都變了不就是所有快取都失效了,那就快取雪崩啦
這么說吧,如果將redis,定位為資料庫的快取,那通常對于一個表內的資料設計key都是: tableName:pk,這樣能確定是一個表的一條資料;
在更新這個表的時候我們必然是可以知道tableName以及pk的.這樣就可以直接定位到redis中的對應快取資料了;
至于你想通過redis里做復雜查詢,我認為可以通過多次取redis資料:
a join b on a.pk = b.pk 這中情況,你可以mget a:pk b:pk;
至于redis與資料庫的資料的冪等性,通常可以通過訊息佇列的訊息消費情況來做異步更新;
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/53720.html
標籤:Web 開發
下一篇:請教jpanel
