【redis知識點整理】 --- springboot2.X使用lettuce連接池集成redis

本文代碼對應的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 !

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章