背景
在最近的項目中,有一個需求是對一個很大的數據庫進行查詢,數據量大概在幾千萬條。但同時對查詢速度的要求也比較高。
這個數據庫之前在沒有使用presto的情況下,使用的是hive,使用hive進行一個簡單的查詢,速度可能在幾分鐘。當然幾分鐘也并不完全是跑sql的時間,這里面包含發請求,查詢數據并且返回數據的時間的總和。但是即使這樣,這樣的速度明顯不能滿足交互式的查詢需求。
我們的下一個解決方案就是presto,在使用了presto之后,查詢速度降到了秒級。但是對于一個前端查詢界面的交互式查詢來說,十幾秒仍然是一個不能接受的時間。
雖然presto相比hive已經快了很多(facebook官方宣稱的是10倍),但是對分頁的支持不是很友好。我在使用的時候是自己在后端實現的分頁。
在這種情況下應用緩存實屬無奈之舉。講道理,優化應從底層開始,自底而上。上層優化的方式和效率感覺都很有局限。
<!--more-->
為什么要使用緩存
前端查詢中,單次查詢的匹配數據量有可能會達到上百甚至上千條,在前端中肯定是需要分頁展示的。就算每次查詢10條數據,整個查詢也要耗時6-8s的時間。想象一下,每翻一頁等10s的場景。
所以,此時使用redis緩存。減少請求數據庫的次數。將匹配的數據一并存入數據庫。這樣只有在第一次查詢時耗費長一點,一旦查詢完成,用戶點擊下一頁就是毫秒級別的操作了。
使用redistemplate
spring封裝了一個比較強大的模板,也就是redistemplate,方便在開發的時候操作redis緩存。在redis中可以存儲string、list、set、hash、zset。下面將針對list和hash分別介紹。
list
redis中的list為簡單的字符串列表,常見的有下面幾種操作。
haskey
判斷一個鍵是否存在,只需要調用haskey
就可以了。假設這個key是test
,具體用法如下。
1
2
3
4
5
|
if (redistemplate.haskey( "test" )) { system.out.println( "存在" ); } else { system.out.println( "不存在" ); } |
range
該函數用于從redis緩存中獲取指定區間的數據。具體用法如下。
1
2
3
4
5
6
7
8
9
10
11
|
if (redistemplate.haskey( "test" )) { // 該鍵的值為 [4, 3, 2, 1] system.out.println(redistemplate.opsforlist().range( "test" , 0 , 0 )); // [4] system.out.println(redistemplate.opsforlist().range( "test" , 0 , 1 )); // [4, 3] system.out.println(redistemplate.opsforlist().range( "test" , 0 , 2 )); // [4, 3, 2] system.out.println(redistemplate.opsforlist().range( "test" , 0 , 3 )); // [4, 3, 2, 1] system.out.println(redistemplate.opsforlist().range( "test" , 0 , 4 )); // [4, 3, 2, 1] system.out.println(redistemplate.opsforlist().range( "test" , 0 , 5 )); // [4, 3, 2, 1] system.out.println(redistemplate.opsforlist().range( "test" , 0 , - 1 )); // [4, 3, 2, 1] 如果結束位是-1, 則表示取所有的值 } |
delete
刪除某個鍵。
1
2
3
4
5
6
7
8
9
10
|
list<string> test = new arraylist<>(); test.add( "1" ); test.add( "2" ); test.add( "3" ); test.add( "4" ); redistemplate.opsforlist().rightpushall( "test" , test); system.out.println(redistemplate.opsforlist().range( "test" , 0 , - 1 )); // [1, 2, 3, 4] redistemplate.delete( "test" ); system.out.println(redistemplate.opsforlist().range( "test" , 0 , - 1 )); // [] |
size
獲取該鍵的集合長度。
1
2
3
4
5
6
7
8
|
list<string> test = new arraylist<>(); test.add( "1" ); test.add( "2" ); test.add( "3" ); test.add( "4" ); redistemplate.opsforlist().rightpushall( "test" , test); system.out.println(redistemplate.opsforlist().size( "test" )); // 4 |
leftpush
我們把存放這個值的地方想象成如圖所示的容器。
container
并且取數據總是從左邊取,但是存數據可以從左也可以從右。左就是leftpush
,右就是rightpush
。leftpush如下圖所示。
left-push
用法如下。
1
2
3
4
5
|
for ( int i = 0 ; i < 4 ; i++) { integer value = i + 1 ; redistemplate.opsforlist().leftpush( "test" , value.tostring()); system.out.println(redistemplate.opsforlist().range( "test" , 0 , - 1 )); } |
控制臺輸出的結果如下。
[1]
[2, 1]
[3, 2, 1]
[4, 3, 2, 1]
leftpushall
基本和leftpush一樣,只不過是一次性的將list入棧。
1
2
3
4
5
6
7
|
list<string> test = new arraylist<>(); test.add( "1" ); test.add( "2" ); test.add( "3" ); test.add( "4" ); redistemplate.opsforlist().leftpushall( "test" , test); system.out.println(redistemplate.opsforlist().range( "test" , 0 , - 1 )); // [4, 3, 2, 1] |
當然你也可以這樣
1
2
|
redistemplate.opsforlist().leftpushall( "test" , test); system.out.println(redistemplate.opsforlist().range( "test" , 0 , - 1 )); // [4, 3, 2, 1] |
leftpushifpresent
跟leftpush
是同樣的操作,唯一的不同是,當且僅當key存在時,才會更新key的值。如果key不存在則不會對數據進行任何操作。
1
2
3
4
5
|
redistemplate.delete( "test" ); redistemplate.opsforlist().leftpushifpresent( "test" , "1" ); redistemplate.opsforlist().leftpushifpresent( "test" , "2" ); system.out.println(redistemplate.opsforlist().range( "test" , 0 , - 1 )); // [] |
leftpop
該函數用于移除上面我們抽象的容器中的最左邊的一個元素。
1
2
3
4
5
6
7
8
9
10
11
12
|
list<string> test = new arraylist<>(); test.add( "1" ); test.add( "2" ); test.add( "3" ); test.add( "4" ); redistemplate.opsforlist().rightpushall( "test" , test); redistemplate.opsforlist().leftpop( "test" ); // [2, 3, 4] redistemplate.opsforlist().leftpop( "test" ); // [3, 4] redistemplate.opsforlist().leftpop( "test" ); // [4] redistemplate.opsforlist().leftpop( "test" ); // [] redistemplate.opsforlist().leftpop( "test" ); // [] |
值得注意的是,當返回為空后,在redis中這個key也不復存在了。如果此時再調用leftpushifpresent,是無法再添加數據的。有代碼有真相。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
list<string> test = new arraylist<>(); test.add( "1" ); test.add( "2" ); test.add( "3" ); test.add( "4" ); redistemplate.opsforlist().rightpushall( "test" , test); redistemplate.opsforlist().leftpop( "test" ); // [2, 3, 4] redistemplate.opsforlist().leftpop( "test" ); // [3, 4] redistemplate.opsforlist().leftpop( "test" ); // [4] redistemplate.opsforlist().leftpop( "test" ); // [] redistemplate.opsforlist().leftpop( "test" ); // [] redistemplate.opsforlist().leftpushifpresent( "test" , "1" ); // [] redistemplate.opsforlist().leftpushifpresent( "test" , "1" ); // [] |
rightpush
rightpush如下圖所示。
right-push
用法如下。
1
2
3
4
5
|
for ( int i = 0 ; i < 4 ; i++) { integer value = i + 1 ; redistemplate.opsforlist().leftpush( "test" , value.tostring()); system.out.println(redistemplate.opsforlist().range( "test" , 0 , - 1 )); } |
控制臺輸出的結果如下。
[1]
[1, 2]
[1, 2, 3]
[1, 2, 3, 4]
rightpushall
同rightpush,一次性將list存入。
1
2
3
4
5
6
7
|
list<string> test = new arraylist<>(); test.add( "1" ); test.add( "2" ); test.add( "3" ); test.add( "4" ); redistemplate.opsforlist().leftpushall( "test" , test); system.out.println(redistemplate.opsforlist().range( "test" , 0 , - 1 )); // [1, 2, 3, 4] |
當然你也可以這樣。
1
2
|
redistemplate.opsforlist().rightpushall( "test" , "1" , "2" , "3" , "4" ); system.out.println(redistemplate.opsforlist().range( "test" , 0 , - 1 )); // [1, 2, 3, 4] |
rightpushifpresent
跟rightpush
是同樣的操作,唯一的不同是,當且僅當key存在時,才會更新key的值。如果key不存在則不會對數據進行任何操作。
1
2
3
4
5
|
redistemplate.delete( "test" ); redistemplate.opsforlist().rightpushifpresent( "test" , "1" ); redistemplate.opsforlist().rightpushifpresent( "test" , "2" ); system.out.println(redistemplate.opsforlist().range( "test" , 0 , - 1 )); // [] |
rightpop
該函數用于移除上面我們抽象的容器中的最右邊的一個元素。
1
2
3
4
5
6
7
8
9
10
11
12
|
list<string> test = new arraylist<>(); test.add( "1" ); test.add( "2" ); test.add( "3" ); test.add( "4" ); redistemplate.opsforlist().rightpushall( "test" , test); redistemplate.opsforlist().rightpop( "test" ); // [1, 2, 3] redistemplate.opsforlist().rightpop( "test" ); // [1, 2] redistemplate.opsforlist().rightpop( "test" ); // [1] redistemplate.opsforlist().rightpop( "test" ); // [] redistemplate.opsforlist().rightpop( "test" ); // [] |
與leftpop一樣,返回空之后,再調用rightpushifpresent,是無法再添加數據的。
index
獲取list中指定位置的元素。
1
2
3
4
5
6
7
8
9
10
|
if (redistemplate.haskey( "test" )) { // 該鍵的值為 [1, 2, 3, 4] system.out.println(redistemplate.opsforlist().index( "test" , - 1 )); // 4 system.out.println(redistemplate.opsforlist().index( "test" , 0 )); // 1 system.out.println(redistemplate.opsforlist().index( "test" , 1 )); // 2 system.out.println(redistemplate.opsforlist().index( "test" , 2 )); // 3 system.out.println(redistemplate.opsforlist().index( "test" , 3 )); // 4 system.out.println(redistemplate.opsforlist().index( "test" , 4 )); // null system.out.println(redistemplate.opsforlist().index( "test" , 5 )); // null } |
值得注意的有兩點。一個是如果下標是-1
的話,則會返回list最后一個元素,另一個如果數組下標越界,則會返回null
。
trim
用于截取指定區間的元素,可能你會理解成與range是一樣的作用。看了下面的代碼之后應該就會立刻理解。
1
2
3
4
5
6
7
8
|
list<string> test = new arraylist<>(); test.add( "1" ); test.add( "2" ); test.add( "3" ); test.add( "4" ); redistemplate.opsforlist().rightpushall( "test" , test); // [1, 2, 3, 4] redistemplate.opsforlist().trim( "test" , 0 , 2 ); // [1, 2, 3] |
其實作用完全不一樣。range
是獲取指定區間內的數據,而trim
是留下指定區間的數據,刪除不在區間的所有數據。trim
是void
,不會返回任何數據。
remove
用于移除鍵中指定的元素。接受3個參數,分別是緩存的鍵名,計數事件,要移除的值。計數事件可以傳入的有三個值,分別是-1
、0
、1
。
-1
代表從存儲容器的最右邊開始,刪除一個與要移除的值匹配的數據;0
代表刪除所有與傳入值匹配的數據;1
代表從存儲容器的最左邊開始,刪除一個與要移除的值匹配的數據。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
list<string> test = new arraylist<>(); test.add( "1" ); test.add( "2" ); test.add( "3" ); test.add( "4" ); test.add( "4" ); test.add( "3" ); test.add( "2" ); test.add( "1" ); redistemplate.opsforlist().rightpushall( "test" , test); // [1, 2, 3, 4, 4, 3, 2, 1] // 當計數事件是-1、傳入值是1時 redistemplate.opsforlist().remove( "test" , - 1 , "1" ); // [1, 2, 3, 4, 4, 3, 2] // 當計數事件是1,傳入值是1時 redistemplate.opsforlist().remove( "test" , 1 , "1" ); // [2, 3, 4, 4, 3, 2] // 當計數事件是0,傳入值是4時 redistemplate.opsforlist().remove( "test" , 0 , "4" ); // [2, 3, 3, 2] |
rightpopandleftpush
該函數用于操作兩個鍵之間的數據,接受三個參數,分別是源key、目標key。該函數會將源key進行rightpop,再將返回的值,作為輸入參數,在目標key上進行leftpush。具體代碼如下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
list<string> test = new arraylist<>(); test.add( "1" ); test.add( "2" ); test.add( "3" ); test.add( "4" ); list<string> test2 = new arraylist<>(); test2.add( "1" ); test2.add( "2" ); test2.add( "3" ); redistemplate.opsforlist().rightpushall( "test" , test); // [1, 2, 3, 4] redistemplate.opsforlist().rightpushall( "test2" , test2); // [1, 2, 3] redistemplate.opsforlist().rightpopandleftpush( "test" , "test2" ); system.out.println(redistemplate.opsforlist().range( "test" , 0 , - 1 )); // [1, 2, 3] system.out.println(redistemplate.opsforlist().range( "test2" , 0 , - 1 )); // [4, 1, 2, 3] |
hash
存儲類型為hash其實很好理解。在上述的list
中,一個redis的key可以理解為一個list,而在hash
中,一個redis的key可以理解為一個hashmap。
put
用于寫入數據。
1
2
3
4
5
6
7
8
|
list<string> list = new arraylist<>(); list.add( "1" ); list.add( "2" ); list.add( "3" ); list.add( "4" ); redistemplate.opsforhash().put( "test" , "map" , list.tostring()); // [1, 2, 3, 4] redistemplate.opsforhash().put( "test" , "isadmin" , true ); // true |
putall
用于一次性向一個hash鍵中添加多個key。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
list<string> list = new arraylist<>(); list.add( "1" ); list.add( "2" ); list.add( "3" ); list.add( "4" ); list<string> list2 = new arraylist<>(); list2.add( "5" ); list2.add( "6" ); list2.add( "7" ); list2.add( "8" ); map<string, string> valuemap = new hashmap<>(); valuemap.put( "map1" , list.tostring()); valuemap.put( "map2" , list2.tostring()); redistemplate.opsforhash().putall( "test" , valuemap); // {map2=[5, 6, 7, 8], map1=[1, 2, 3, 4]} |
putifabsent
用于向一個hash鍵中寫入數據。當key在hash鍵中已經存在時,則不會寫入任何數據,只有在hash鍵中不存在這個key時,才會寫入數據。
同時,如果連這個hash鍵都不存在,redistemplate會新建一個hash鍵,再寫入key。
1
2
3
4
5
6
7
|
list<string> list = new arraylist<>(); list.add( "1" ); list.add( "2" ); list.add( "3" ); list.add( "4" ); redistemplate.opsforhash().putifabsent( "test" , "map" , list.tostring()); system.out.println(redistemplate.opsforhash().entries( "test" )); // {map=[1, 2, 3, 4]} |
get
用于獲取數據。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
list<string> list = new arraylist<>(); list.add( "1" ); list.add( "2" ); list.add( "3" ); list.add( "4" ); redistemplate.opsforhash().put( "test" , "map" , list.tostring()); redistemplate.opsforhash().put( "test" , "isadmin" , true ); system.out.println(redistemplate.opsforhash().get( "test" , "map" )); // [1, 2, 3, 4] system.out.println(redistemplate.opsforhash().get( "test" , "isadmin" )); // true boolean bool = ( boolean ) redistemplate.opsforhash().get( "test" , "isadmin" ); system.out.println(bool); // true string str = redistemplate.opsforhash().get( "test" , "map" ).tostring(); list<string> array = jsonarray.parsearray(str, string. class ); system.out.println(array.size()); // 4 |
值得注意的是,使用get
函數獲取的數據都是object類型。
所以需要使用類型與上述例子中的布爾類型的話,則需要強制轉換一次。list
類型則可以使用fastjson
這種工具來進行轉換。轉換的例子已列舉在上述代碼中。
delete
用于刪除一個hash鍵中的key。可以理解為刪除一個map中的某個key。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
list<string> list = new arraylist<>(); list.add( "1" ); list.add( "2" ); list.add( "3" ); list.add( "4" ); list<string> list2 = new arraylist<>(); list2.add( "5" ); list2.add( "6" ); list2.add( "7" ); list2.add( "8" ); map<string, string> valuemap = new hashmap<>(); valuemap.put( "map1" , list.tostring()); valuemap.put( "map2" , list2.tostring()); redistemplate.opsforhash().putall( "test" , valuemap); // {map2=[5, 6, 7, 8], map1=[1, 2, 3, 4]} redistemplate.opsforhash().delete( "test" , "map1" ); // {map2=[5, 6, 7, 8]} |
values
用于獲取一個hash類型的鍵的所有值。
1
2
3
4
5
6
7
8
9
10
|
list<string> list = new arraylist<>(); list.add( "1" ); list.add( "2" ); list.add( "3" ); list.add( "4" ); redistemplate.opsforhash().put( "test" , "map" , list.tostring()); redistemplate.opsforhash().put( "test" , "isadmin" , true ); system.out.println(redistemplate.opsforhash().values( "test" )); // [[1, 2, 3, 4], true] |
entries
用于以map的格式獲取一個hash鍵的所有值。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
list<string> list = new arraylist<>(); list.add( "1" ); list.add( "2" ); list.add( "3" ); list.add( "4" ); redistemplate.opsforhash().put( "test" , "map" , list.tostring()); redistemplate.opsforhash().put( "test" , "isadmin" , true ); map<string, string> map = redistemplate.opsforhash().entries( "test" ); system.out.println(map.get( "map" )); // [1, 2, 3, 4] system.out.println(map.get( "map" ) instanceof string); // true system.out.println(redistemplate.opsforhash().entries( "test" )); // {a=[1, 2, 3, 4], isadmin=true} |
haskey
用于獲取一個hash鍵中是否含有某個鍵。
1
2
3
4
5
6
7
8
9
10
11
12
|
ist<string> list = new arraylist<>(); list.add( "1" ); list.add( "2" ); list.add( "3" ); list.add( "4" ); redistemplate.opsforhash().put( "test" , "map" , list.tostring()); redistemplate.opsforhash().put( "test" , "isadmin" , true ); system.out.println(redistemplate.opsforhash().haskey( "test" , "map" )); // true system.out.println(redistemplate.opsforhash().haskey( "test" , "b" )); // false system.out.println(redistemplate.opsforhash().haskey( "test" , "isadmin" )); // true |
keys
用于獲取一個hash鍵中所有的鍵。
1
2
3
4
5
6
7
8
9
10
|
list<string> list = new arraylist<>(); list.add( "1" ); list.add( "2" ); list.add( "3" ); list.add( "4" ); redistemplate.opsforhash().put( "test" , "map" , list.tostring()); redistemplate.opsforhash().put( "test" , "isadmin" , true ); system.out.println(redistemplate.opsforhash().keys( "test" )); // [a, isadmin] |
size
用于獲取一個hash鍵中包含的鍵的數量。
1
2
3
4
5
6
7
8
9
10
|
list<string> list = new arraylist<>(); list.add( "1" ); list.add( "2" ); list.add( "3" ); list.add( "4" ); redistemplate.opsforhash().put( "test" , "map" , list.tostring()); redistemplate.opsforhash().put( "test" , "isadmin" , true ); system.out.println(redistemplate.opsforhash().size( "test" )); // 2 |
increment
用于讓一個hash鍵中的某個key,根據傳入的值進行累加。傳入的數值只能是double
或者long
,不接受浮點型
1
2
3
4
5
6
|
redistemplate.opsforhash().increment( "test" , "a" , 3 ); redistemplate.opsforhash().increment( "test" , "a" , - 3 ); redistemplate.opsforhash().increment( "test" , "a" , 1 ); redistemplate.opsforhash().increment( "test" , "a" , 0 ); system.out.println(redistemplate.opsforhash().entries( "test" )); // {a=1} |
multiget
用于批量的獲取一個hash鍵中多個key的值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
list<string> list = new arraylist<>(); list.add( "1" ); list.add( "2" ); list.add( "3" ); list.add( "4" ); list<string> list2 = new arraylist<>(); list2.add( "5" ); list2.add( "6" ); list2.add( "7" ); list2.add( "8" ); redistemplate.opsforhash().put( "test" , "map1" , list.tostring()); // [1, 2, 3, 4] redistemplate.opsforhash().put( "test" , "map2" , list2.tostring()); // [5, 6, 7, 8] list<string> keys = new arraylist<>(); keys.add( "map1" ); keys.add( "map2" ); system.out.println(redistemplate.opsforhash().multiget( "test" , keys)); // [[1, 2, 3, 4], [5, 6, 7, 8]] system.out.println(redistemplate.opsforhash().multiget( "test" , keys) instanceof list); // true |
scan
獲取所以匹配條件的hash鍵中key的值。我查過一些資料,大部分寫的是無法模糊匹配,我自己嘗試了一下,其實是可以的。如下,使用scan
模糊匹配hash鍵的key中,帶scan
的key。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
list<string> list = new arraylist<>(); list.add( "1" ); list.add( "2" ); list.add( "3" ); list.add( "4" ); list<string> list2 = new arraylist<>(); list2.add( "5" ); list2.add( "6" ); list2.add( "7" ); list2.add( "8" ); list<string> list3 = new arraylist<>(); list3.add( "9" ); list3.add( "10" ); list3.add( "11" ); list3.add( "12" ); map<string, string> valuemap = new hashmap<>(); valuemap.put( "map1" , list.tostring()); valuemap.put( "scan_map2" , list2.tostring()); valuemap.put( "map3" , list3.tostring()); redistemplate.opsforhash().putall( "test" , valuemap); // {scan_map2=[5, 6, 7, 8], map3=[9, 10, 11, 12], map1=[1, 2, 3, 4]} cursor<map.entry<string, string>> cursor = redistemplate.opsforhash().scan( "test" , scanoptions.scanoptions().match( "*scan*" ).build()); if (cursor.hasnext()) { while (cursor.hasnext()) { map.entry<string, string> entry = cursor.next(); system.out.println(entry.getvalue()); // [5, 6, 7, 8] } } |
引入redistemplate
如果大家看懂了怎么用,就可以將redistemplate引入項目中了。
引入pom依賴
1
2
3
4
5
|
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-data-redis</artifactid> <version> 2.0 . 5 .release</version> </dependency> |
新建配置文件
然后需要新建一個redisconfig
配置文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
package com.detectivehlh; import com.fasterxml.jackson.annotation.jsonautodetect; import com.fasterxml.jackson.annotation.propertyaccessor; import com.fasterxml.jackson.databind.objectmapper; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; import org.springframework.data.redis.connection.redisconnectionfactory; import org.springframework.data.redis.core.redistemplate; import org.springframework.data.redis.core.stringredistemplate; import org.springframework.data.redis.serializer.jackson2jsonredisserializer; /** * redisconfig * * @author lunhao hu * @date 2019-01-17 15:12 **/ @configuration public class redisconfig { @bean public redistemplate<string, string> redistemplate(redisconnectionfactory factory) { objectmapper om = new objectmapper(); om.setvisibility(propertyaccessor.all, jsonautodetect.visibility.any); om.enabledefaulttyping(objectmapper.defaulttyping.non_final); //redis序列化 jackson2jsonredisserializer jackson2jsonredisserializer = new jackson2jsonredisserializer(object. class ); jackson2jsonredisserializer.setobjectmapper(om); stringredistemplate template = new stringredistemplate(factory); template.setvalueserializer(jackson2jsonredisserializer); template.sethashkeyserializer(jackson2jsonredisserializer); template.sethashvalueserializer(jackson2jsonredisserializer); template.setvalueserializer(jackson2jsonredisserializer); template.afterpropertiesset(); return template; } } |
注入
將redistemplate注入到需要使用的地方。
1
2
|
@autowired private redistemplate redistemplate; |
寫在后面
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://segmentfault.com/a/1190000017940126#leftPush