原文博客地址: pjmike的博客html
在實際項目開發過程當中,相信不少人都有用到過 redis 這個NoSQL,這篇文章就詳細講講springboot如何整合 redisjava
簡單介紹下Redis:git
Redis是一個開源的使用 ANSI C語言編寫,支持網絡,可基於內存也可持久化的日誌型,Key-Value數據庫,並提供了多種語言的 API ,相比
Memcached
它支持存儲的類型相對更多 (字符,哈希,集合,有序集合,列表等),同時Redis是線程安全的。github
在後面 springboot 整合 redis 的時候會用到鏈接池,因此這裏先來介紹下 Redis中的鏈接池:web
客戶端鏈接 Redis 使用的是 TCP協議,直連的方式每次須要創建 TCP鏈接,而鏈接池的方式是能夠預先初始化好客戶端鏈接,因此每次只須要從 鏈接池借用便可,而借用和歸還操做是在本地進行的,只有少許的併發同步開銷,遠遠小於新建TCP鏈接的開銷。另外,直連的方式沒法限制 redis客戶端對象的個數,在極端狀況下可能會形成鏈接泄漏,而鏈接池的形式能夠有效的保護和控制資源的使用。redis
下面以Jedis客戶端爲例,再來總結下 客戶端直連方式和鏈接池方式的對比spring
優勢 | 缺點 | |
---|---|---|
直連 | 簡單方便,適用於少許長期鏈接的場景 | 1. 存在每次新建/關閉TCP鏈接開銷 2. 資源沒法控制,極端狀況下出現鏈接泄漏 3. Jedis對象線程不安全(Lettuce對象是線程安全的) |
鏈接池 | 1. 無需每次鏈接生成Jedis對象,下降開銷 2. 使用鏈接池的形式保護和控制資源的使用 | 相對於直連,使用更加麻煩,尤爲在資源的管理上須要不少參數來保證,一旦規劃不合理也會出現問題 |
redis官方提供的java client有如圖所示幾種: sql
比較突出的是 Lettuce 和 jedis。Lettuce 和 jedis 的都是鏈接 Redis Server的客戶端,Jedis 在實現上是直連 redis server,多線程環境下非線程安全,除非使用鏈接池,爲每一個 redis實例增長 物理鏈接。Lettuce 是 一種可伸縮,線程安全,徹底非阻塞的Redis客戶端,多個線程能夠共享一個RedisConnection,它利用Netty NIO 框架來高效地管理多個鏈接,從而提供了異步和同步數據訪問方式,用於構建非阻塞的反應性應用程序。數據庫
在 springboot 1.5.x版本的默認的Redis客戶端是 Jedis
實現的,springboot 2.x版本中默認客戶端是用 lettuce
實現的。segmentfault
下面介紹 springboot 2.0
分別使用 jedis
和 lettuce
集成 redis服務
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
複製代碼
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=root
# 鏈接池最大鏈接數(使用負值表示沒有限制) 默認爲8
spring.redis.lettuce.pool.max-active=8
# 鏈接池最大阻塞等待時間(使用負值表示沒有限制) 默認爲-1
spring.redis.lettuce.pool.max-wait=-1ms
# 鏈接池中的最大空閒鏈接 默認爲8
spring.redis.lettuce.pool.max-idle=8
# 鏈接池中的最小空閒鏈接 默認爲 0
spring.redis.lettuce.pool.min-idle=0
複製代碼
默認狀況下的模板只能支持 RedisTemplate<String,String>
,只能存入字符串,不少時候,咱們須要自定義 RedisTemplate ,設置序列化器,這樣咱們能夠很方便的操做實例對象。以下所示:
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Serializable> redisTemplate(LettuceConnectionFactory connectionFactory) {
RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setConnectionFactory(connectionFactory);
return redisTemplate;
}
}
複製代碼
public class User implements Serializable {
private static final long serialVersionUID = 4220515347228129741L;
private Integer id;
private String username;
private Integer age;
public User(Integer id, String username, Integer age) {
this.id = id;
this.username = username;
this.age = age;
}
public User() {
}
//getter/setter 省略
}
複製代碼
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisTest {
private Logger logger = LoggerFactory.getLogger(RedisTest.class);
@Autowired
private RedisTemplate<String, Serializable> redisTemplate;
@Test
public void test() {
String key = "user:1";
redisTemplate.opsForValue().set(key, new User(1,"pjmike",20));
User user = (User) redisTemplate.opsForValue().get(key);
logger.info("uesr: "+user.toString());
}
}
複製代碼
由於 springboot2.0中默認是使用 Lettuce來集成Redis服務,spring-boot-starter-data-redis
默認只引入了 Lettuce
包,並無引入 jedis
包支持。因此在咱們須要手動引入 jedis
的包,並排除掉 lettuce
的包,pom.xml配置以下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
複製代碼
使用jedis的鏈接池
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=root
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.max-wait=-1ms
spring.redis.jedis.pool.min-idle=0
spring.redis.jedis.pool.max-active=8
複製代碼
由於在 springoot 2.x版本中,默認採用的是 Lettuce實現的,因此沒法初始化出 Jedis的鏈接對象 JedisConnectionFactory
,因此咱們須要手動配置並注入:
public class RedisConfig {
@Bean
JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory factory = new JedisConnectionFactory();
return factory;
}
複製代碼
可是啓動項目後發現報出了以下的異常:
redis鏈接失敗,springboot2.x經過以上方式集成Redis並不會讀取配置文件中的 spring.redis.host
等這樣的配置,須要手動配置,以下:
@Configuration
public class RedisConfig2 {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.password}")
private String password;
@Bean
public RedisTemplate<String, Serializable> redisTemplate(JedisConnectionFactory connectionFactory) {
RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setConnectionFactory(jedisConnectionFactory());
return redisTemplate;
}
@Bean
public JedisConnectionFactory jedisConnectionFactory() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
config.setHostName(host);
config.setPort(port);
config.setPassword(RedisPassword.of(password));
JedisConnectionFactory connectionFactory = new JedisConnectionFactory(config);
return connectionFactory;
}
}
複製代碼
經過以上方式就能夠鏈接上 redis了,不過這裏要提醒的一點就是,在springboot 2.x版本中 JedisConnectionFactory
設置鏈接的方法已過期,如圖所示:
在 springboot 2.x
版本中推薦使用 RedisStandaloneConfiguration
類來設置鏈接的端口,地址等屬性
而後是單元測試,與上面 Lettuce
的例子代碼同樣,而且測試經過。
上面介紹springboot 2.x版本如何經過 Jedis 和 Lettuce 來集成Redis服務,源代碼地址以下:github.com/pjmike/spri…