国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Spring學習筆記之RedisTemplate的配置與使用教程

Spring學習筆記之RedisTemplate的配置與使用教程

2021-05-08 12:18一灰灰 Java教程

這篇文章主要給大家介紹了關于Spring學習筆記之RedisTemplate配置與使用的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用spring具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

前言

spring針對redis的使用,封裝了一個比較強大的template以方便使用;之前在spring的生態圈中也使用過redis,但直接使用jedis進行相應的交互操作,現在正好來看一下redistemplate是怎么實現的,以及使用起來是否更加便利

i. 基本配置

 

1. 依賴

依然是采用jedis進行連接池管理,因此除了引入 spring-data-redis之外,再加上jedis依賴,pom文件中添加

?
1
2
3
4
5
6
7
8
9
10
11
<dependency>
 <groupid>org.springframework.data</groupid>
 <artifactid>spring-data-redis</artifactid>
 <version>1.8.4.release</version>
</dependency>
 
<dependency>
 <groupid>redis.clients</groupid>
 <artifactid>jedis</artifactid>
 <version>2.9.0</version>
</dependency>

如果需要指定序列化相關參數,也可以引入jackson,本篇為簡單入門級,就不加這個了

2. 配置文件

準備redis相關的配置參數,常見的有host, port, password, timeout…,下面是一份簡單的配置,并給出了相應的含義

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
redis.hostname=127.0.0.1
redis.port=6379
redis.password=https://blog.hhui.top
# 連接超時時間
redis.timeout=10000
 
#最大空閑數
redis.maxidle=300
#控制一個pool可分配多少個jedis實例,用來替換上面的redis.maxactive,如果是jedis 2.4以后用該屬性
redis.maxtotal=1000
#最大建立連接等待時間。如果超過此時間將接到異常。設為-1表示無限制。
redis.maxwaitmillis=1000
#連接的最小空閑時間 默認1800000毫秒(30分鐘)
redis.minevictableidletimemillis=300000
#每次釋放連接的最大數目,默認3
redis.numtestsperevictionrun=1024
#逐出掃描的時間間隔(毫秒) 如果為負數,則不運行逐出線程, 默認-1
redis.timebetweenevictionrunsmillis=30000
#是否在從池中取出連接前進行檢驗,如果檢驗失敗,則從池中去除連接并嘗試取出另一個
redis.testonborrow=true
#在空閑時檢查有效性, 默認false
redis.testwhileidle=true

說明

redis密碼請一定記得設置,特別是在允許遠程訪問的時候,如果沒有密碼,默認端口號,很容易就被是掃描注入腳本,然后開始給人挖礦(親身經歷…)

ii. 使用與測試

 

根據一般的思路,首先是得加載上面的配置,創建redis連接池,然后再實例化redistemplate對象,最后持有這個實力開始各種讀寫操作

1. 配置類

使用javaconfig的方式來配置,主要是兩個bean,讀取配置文件設置各種參數的redisconnectionfactory以及預期的redistemplate

?
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
@configuration
@propertysource("classpath:redis.properties")
public class redisconfig extends jcacheconfigurersupport {
 @autowired
 private environment environment;
 
 @bean
 public redisconnectionfactory redisconnectionfactory() {
 jedisconnectionfactory fac = new jedisconnectionfactory();
 fac.sethostname(environment.getproperty("redis.hostname"));
 fac.setport(integer.parseint(environment.getproperty("redis.port")));
 fac.setpassword(environment.getproperty("redis.password"));
 fac.settimeout(integer.parseint(environment.getproperty("redis.timeout")));
 fac.getpoolconfig().setmaxidle(integer.parseint(environment.getproperty("redis.maxidle")));
 fac.getpoolconfig().setmaxtotal(integer.parseint(environment.getproperty("redis.maxtotal")));
 fac.getpoolconfig().setmaxwaitmillis(integer.parseint(environment.getproperty("redis.maxwaitmillis")));
 fac.getpoolconfig().setminevictableidletimemillis(
 integer.parseint(environment.getproperty("redis.minevictableidletimemillis")));
 fac.getpoolconfig()
 .setnumtestsperevictionrun(integer.parseint(environment.getproperty("redis.numtestsperevictionrun")));
 fac.getpoolconfig().settimebetweenevictionrunsmillis(
 integer.parseint(environment.getproperty("redis.timebetweenevictionrunsmillis")));
 fac.getpoolconfig().settestonborrow(boolean.parseboolean(environment.getproperty("redis.testonborrow")));
 fac.getpoolconfig().settestwhileidle(boolean.parseboolean(environment.getproperty("redis.testwhileidle")));
 return fac;
 }
 
 @bean
 public redistemplate<string, string> redistemplate(redisconnectionfactory redisconnectionfactory) {
 redistemplate<string, string> redis = new redistemplate<>();
 redis.setconnectionfactory(redisconnectionfactory);
 redis.afterpropertiesset();
 return redis;
 }
}

2. 測試與使用

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@runwith(springjunit4classrunner.class)
@contextconfiguration(classes = {redisconfig.class})
public class redistest {
 
 @autowired
 private redistemplate<string, string> redistemplate;
 
 @test
 public void testredisobj() {
 map<string, object> properties = new hashmap<>();
 properties.put("123", "hello");
 properties.put("abc", 456);
 
 redistemplate.opsforhash().putall("hash", properties);
 
 map<object, object> ans = redistemplate.opsforhash().entries("hash");
 system.out.println("ans: " + ans);
 }
}

執行后輸出如下

?
1
ans: {123=hello, abc=456}

從上面的配置與實現來看,是很簡單的了,基本上沒有繞什么圈子,但是使用redis-cli連上去,卻查詢不到 hash 這個key的內容

?
1
2
3
4
127.0.0.1:6379> get hash
(nil)
127.0.0.1:6379> keys *
1) "\xac\xed\x00\x05t\x00\x04hash"

使用代碼去查沒問題,直接控制臺連接,發現這個key和我們預期的不一樣,多了一些前綴,why ?

3. 序列化問題

為了解決上面的問題,只能debug進去,看下是什么引起的了

對應源碼位置:

?
1
2
3
4
5
6
// org.springframework.data.redis.core.abstractoperations#rawkey
 
byte[] rawkey(object key) {
 assert.notnull(key, "non null key required");
 return this.keyserializer() == null && key instanceof byte[] ? (byte[])((byte[])key) : this.keyserializer().serialize(key);
}

可以看到這個key不是我們預期的 key.getbytes(), 而是調用了this.keyserializer().serialize(key),而debug的結果,默認serializer是jdkserializationredisserializer

Spring學習筆記之RedisTemplate的配置與使用教程

然后就是順藤摸瓜一步一步深入進去,鏈路如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// org.springframework.core.serializer.support.serializingconverter#convert
 
// org.springframework.core.serializer.defaultserializer#serialize
 
public class defaultserializer implements serializer<object> {
 public defaultserializer() {
 }
 
 public void serialize(object object, outputstream outputstream) throws ioexception {
 if (!(object instanceof serializable)) {
 throw new illegalargumentexception(this.getclass().getsimplename() + " requires a serializable payload but received an object of type [" + object.getclass().getname() + "]");
 } else {
 objectoutputstream objectoutputstream = new objectoutputstream(outputstream);
 objectoutputstream.writeobject(object);
 objectoutputstream.flush();
 }
 }
}

所以具體的實現很清晰了,就是 objectoutputstream,這個東西就是java中最原始的序列化反序列流工具,會包含類型信息,所以會帶上那串前綴了

所以要解決這個問題,也比較明確了,替換掉原生的jdkserializationredisserializer,改為string的方式,正好提供了一個stringredisserializer,所以在redistemplate的配置處,稍稍修改

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@bean
public redistemplate<string, string> redistemplate(redisconnectionfactory redisconnectionfactory) {
 redistemplate<string, string> redis = new redistemplate<>();
 redis.setconnectionfactory(redisconnectionfactory);
 
 // 設置redis的string/value的默認序列化方式
 stringredisserializer stringredisserializer = new stringredisserializer();
 redis.setkeyserializer(stringredisserializer);
 redis.setvalueserializer(stringredisserializer);
 redis.sethashkeyserializer(stringredisserializer);
 redis.sethashvalueserializer(stringredisserializer);
 
 redis.afterpropertiesset();
 return redis;
}

再次執行,結果尷尬的事情出現了,拋異常了,類型轉換失敗

?
1
2
3
4
5
6
java.lang.classcastexception: java.lang.integer cannot be cast to java.lang.string
 
 at org.springframework.data.redis.serializer.stringredisserializer.serialize(stringredisserializer.java:33)
 at org.springframework.data.redis.core.abstractoperations.rawhashvalue(abstractoperations.java:171)
 at org.springframework.data.redis.core.defaulthashoperations.putall(defaulthashoperations.java:129)
 ...

看前面的測試用例,map中的value有integer,而stringredisserializer接收的參數必須是string,所以不用這個,自己照樣子重新寫一個兼容掉

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class defaultstrserializer implements redisserializer<object> {
 private final charset charset;
 
 public defaultstrserializer() {
 this(charset.forname("utf8"));
 }
 
 public defaultstrserializer(charset charset) {
 assert.notnull(charset, "charset must not be null!");
 this.charset = charset;
 }
 
 
 @override
 public byte[] serialize(object o) throws serializationexception {
 return o == null ? null : string.valueof(o).getbytes(charset);
 }
 
 @override
 public object deserialize(byte[] bytes) throws serializationexception {
 return bytes == null ? null : new string(bytes, charset);
 
 }
}

然后可以開始愉快的玩耍了,執行完之后測試

?
1
2
3
4
5
6
7
8
keys *
1) "\xac\xed\x00\x05t\x00\x04hash"
2) "hash"
127.0.0.1:6379> hgetall hash
1) "123"
2) "hello"
3) "abc"
4) "456"

iii. redistemplate使用姿勢

 

1. opsforxxx

簡單過來一下redistemplate的使用姿勢,針對不同的數據結構(string, list, zset, hash)讀封裝了比較使用的調用方式 opsforxxx

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// hash 數據結構操作
org.springframework.data.redis.core.redistemplate#opsforhash
 
// list
org.springframework.data.redis.core.redistemplate#opsforlist
 
// string
org.springframework.data.redis.core.redistemplate#opsforvalue
 
// set
org.springframework.data.redis.core.redistemplate#opsforset
 
// zset
org.springframework.data.redis.core.redistemplate#opsforzset

2. execute

除了上面的這種使用方式之外,另外一種常見的就是直接使用execute了,一個簡單的case如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@test
public void testredis() {
 string key = "hello";
 string value = "world";
 redistemplate.execute((rediscallback<void>) con -> {
 con.set(key.getbytes(), value.getbytes());
 return null;
 });
 
 string asn = redistemplate.execute((rediscallback<string>) con -> new string(con.get(key.getbytes())));
 system.out.println(asn);
 
 
 string hkey = "hkey";
 redistemplate.execute((rediscallback<void>) con -> {
 con.hset(hkey.getbytes(), "23".getbytes(), "what".getbytes());
 return null;
 });
 
 map<byte[], byte[]> map = redistemplate.execute((rediscallback<map<byte[], byte[]>>) con -> con.hgetall(hkey.getbytes()));
 for (map.entry<byte[], byte[]> entry : map.entryset()) {
 system.out.println("key: " + new string(entry.getkey()) + " | value: " + new string(entry.getvalue()));
 }
}

輸出結果如下

world
key: 23 | value: what

3. 區別

一個自然而然能想到的問題就是上面的兩種方式有什么區別?

opsforxxx 的底層,就是通過調用execute方式來做的,其主要就是封裝了一些使用姿勢,定義了序列化,使用起來更加的簡單和便捷;這種方式下,帶來的小號就是每次都需要新建一個defaultxxxoperations對象,多繞了一步,基于此是否會帶來額外的性能和內存開銷呢?沒測過,但個人感覺量小的情況下,應該沒什么明顯的影響;而qps很高的情況下,這方便的優化能帶來的幫助,估計也不太大

iv. 其他

 

0. 項目

study-demo/spring-redis

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。

原文鏈接:https://liuyueyi.github.io/hexblog/2018/06/11/180611-SpringRedisTemplate配置與使用/

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 热精品| 免费视频一区 | 黄色高清视频在线观看 | 国产综合在线观看视频 | av中文字幕在线播放 | 日韩av中文在线 | 不用播放器的免费av | 日韩一二三区视频 | 在线精品一区 | 中文字幕第七页 | 国产激情网址 | 一级毛片视频 | 日韩福利影院 | 婷婷综合 | 亚洲欧美激情精品一区二区 | av电影免费观看 | 91电影国产| 午夜精品久久 | 亚洲精品中字 | 欧美精品久久久久久久久老牛影院 | 草久在线视频 | 久久艹天天艹 | 精品国产乱码久久久久久久软件 | 亚洲欧美综合乱码精品成人网 | 九九综合九九 | 日本一区二区视频在线播放 | 黄色在线免费 | 狠狠操综合网 | 可以在线观看的av网站 | 99精品视频在线 | 成人久久久久久久久 | 2018啪一啪 | 91精品国产综合久久久久 | 国产精品视频播放 | 国产在线91 | 国产精品久久久久久久久久久久冷 | 国产精品三级视频 | 欧美视频免费在线 | 亚洲一区在线观看视频 | 黄色小视频在线免费观看 | 欧美a级片在线观看 |