本文代碼對應的github地址:https://github.com/nieandsun/redis-study
不出意外的話,很多公司操作redis應該還是使用的jedis。
當然應該也有公司比較
能耐
,直接把操作redis的所有方法進一步封裝成API或Utils類,然後打成jar包,做成服務供多個部門使用 —》 然後開發者就不必關心真正與redis交互的細節了。— 其實我們公司就是這種姿勢!!!
不知道其他公司到底是怎麼個套路,我覺得這種方式對公司挺好,但是對於我們開發者自身來說,可能就缺少了直面問題 + 解決問題的機會。
其實說實話,我們組也在做一些基礎性的服務,從這個角度來講,貌似每個部門(或許更應該說是每一個coder吧)都希望自己可以直面問題,直面挑戰,然後讓別人使用自己提供的服務!!!
不知道是不是每個人都是這麼想的,但至少我感覺貌似我身邊的好些人都表現出了這種姿態!!!
1 jedis和lettuce簡單比較
-
Jedis
在實現上是直接連接Redis服務器,在多個線程間共享一個Jedis 實例時是線程不安全的
,如果想要在多線程場景下使用Jedis,需要使用連接池,每個線程都使用自己的Jedis實例,當連接數量增多時,會消耗較多的物理資源。 -
與Jedis相比,
lettuce
則完全克服了其線程不安全的缺點:lettuce 是一個可伸縮的線程安全的 Redis客戶端,支持同步、異步和響應式模式。多個線程可以共享一個連接實例, 而不必擔心多線程併發問題。它基於優秀Netty NIO框架構建,支持Redis的更多高級功能。
2 springboot集成redis
2.1 添加依賴
maven依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- lettuce連接池需要依賴下面的jar包 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
2.2 數據源配置
spring:
redis:
database: 0 #使用第幾個數據庫
host: 192.168.65.135 #redis服務器地址
port: 6379 #端口號
password: 123456 #redis服務器連接密碼
timeout: 10000ms # 連接超時時間(毫秒)
lettuce:
pool:
##下面的值其實是lettuce連接池的默認配置,有興趣的可以點進源碼看一下
max-active: 8 #連接池最大連接數(使用負值表示沒有限制)
max-wait: -1ms #連接池最大阻塞等待時間(使用負值表示沒有限制)
max-idle: 8 #連接池中的最大空閒連接
min-idle: 0 #連接池中的最小空閒連接
2.3 配置類
實際上完成2.2就可以了,但是由於springboot默認提供的redis操作模版類 —RedisTemplate實際上爲<Object,Object>類型,但是相信大家都知道,我們平常使用redis,key都會使用一個相對簡單的字符串,因此我們需要自己配置一個RedisTemplate,具體原理可以看一下下面的文章,這裏我不過多敘述 —》但是那篇文章數據源那一塊是有問題的
https://www.cnblogs.com/zeng1994/p/03303c805731afc9aa9c60dbbd32a323.html#!comments
@Configuration
public class RedisConfig {
@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key採用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也採用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式採用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式採用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
3 簡單測試
測試程序如下:
package com.nrsc.redis.learning.simple;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class RedisSimpleDemo {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
public void test1() {
redisTemplate.multi();
redisTemplate.opsForValue().set("k1", "Hello Redis1....");
int i = 100 / 0;
redisTemplate.opsForValue().set("k2", "Hello Redis2....");
redisTemplate.exec();
}
@Test
public void test2() {
stringRedisTemplate.multi();
stringRedisTemplate.opsForValue().set("k1", "Hello Redis1....");
int i = 100 / 0;
stringRedisTemplate.opsForValue().set("k2", "Hello Redis2....");
stringRedisTemplate.exec();
}
}
可以得到的結論:
(1)test1方法運行之後,數據庫裏什麼值都插入不進去,但test2運行後可以插入k1對應的值 —》 說明:
- 我們配置的事務生效了。
- 當然如果想讓StringRedisTemplate可以開啓事務,我們可以按照RedisTemplate一樣配置一個我們自己的StringRedisTemplate
(2)無論是RedisTemplate還是StringRedisTemplate,都使用了我們配置的連接池信息,有興趣的可以通過打斷點的方式看一下RedisTemplate或StringRedisTemplate實例中的connectionFactory,舉例如下:
end !