Jedis連接工具 和 SpringBoot整合Redis


引用學習:https://space.bilibili.com/95256449/

Jedis連接工具

什么是Jedis?

它是官方推薦的Java連接開發工具!使用Java操作 Redis中間件!如果你使用java操作 Redis ,那么要對 jedis 十分的熟悉!

測試

  • 在本地主機進行測試

1、打開 Redis 服務

2、新建maven項目,導入依賴

<!--導入jedis的包-->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.2.0</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.66</version>
</dependency>

3、測試連接

package com.zxh;

import redis.clients.jedis.Jedis;

public class TestPing {
    public static void main(String[] args) {
        // 1、 new Jedis 對象即可
         Jedis jedis = new Jedis("127.0.0.1",6379);
        // jedis 所有的命令就是我們之前學習的所有指令!所以之前的指令學習很重要!
        System.out.println(jedis.ping()); }
}

輸出:

常用API

所有的api命令,就是我們對應的上面學習的指令,一個都沒有變化!

事務

package com.zxh;

import com.alibaba.fastjson.JSONObject;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

public class TestTx {
    public static void main(String[] args) {
        // 建立連接
        Jedis jedis = new Jedis("127.0.0.1", 6379);

        jedis.flushDB();    // 清除當前數據庫

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("username", "zxh");
        jsonObject.put("age", 20);
        String result = jsonObject.toJSONString();

        // 開啟事務
        Transaction multi = jedis.multi();
        try {
            // 命令入隊
            multi.set("user1", result);
            multi.set("user2", result);
            int i = 1/0;    // 制造異常
            //執行事務
            multi.exec();
        } catch (Exception e) { // 拋出異常,取消事務
            multi.discard();    //消事務
            e.printStackTrace();
        } finally {
            System.out.println(jedis.get("user1"));
            System.out.println(jedis.get("user2"));
            jedis.close();  // 關閉連接
        }

    }
}

結果:

SpringBoot整合

准備工作和源碼分析

簡介

SpringBoot 操作數據:spring-data => jpa jdbc mongodb redis!

SpringData 也是和 SpringBoot齊名的項目!

准備工作

1、創建SpringBoot項目

  • 勾選支持項

2、依賴

<!-- redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

源碼分析

進入 Redis 的依賴可以找到,底層使用的就是 Jedis,不過可以看到還有另外一個 lettuce

說明

Jedis:采用的是直連,所以在多個線程操作的話,是不安全的!如果想要避免不安全,使用 Jedis pool 連接池! 更像 BIO(Blocking I/O,阻塞IO)

lettuce:采用netty,實例可以在多個線程中進行共享,不存在線程不安全的情況!可以減少線程數據量,更像 NIO(Nonblocking I/O,非阻塞IO)

 NIO和BIO解釋

Netty是一款基於NIO(Nonblocking I/O,非阻塞IO)開發的網絡通信框架,對比於BIO(Blocking I/O,阻塞IO),他的並發性能得到了很大提高

兩張圖讓你了解BIO和NIO的區別:

                阻塞IO

                非阻塞IO

這兩張圖可以看出,NIO的單線程能處理連接的數量比BIO要高出很多,而為什么單線程能處理更多的連接呢?原因就是圖二中出現的Selector

當一個連接建立之后,它有兩個步驟要做:

  • 第一步是接收客戶端發過來的全部數據

  • 第二步是服務端處理完請求之后返回response客戶端

NIO和BIO的區別主要是在第一步:

  • 在BIO中,等待客戶端發數據這個過程是阻塞的,這樣就造成了一個線程只能處理一個請求的情況,而機器能支持的最大線程數是有限的,這就是為什么BIO不能支持高並發的原因。

  • 而NIO中,當一個Socket 建立之后,Thread 並不會阻塞接收這個 Socket,而是將這個請求交給 Selector,Selector 會不斷的去遍歷所有的 Socket,一旦有一個Socket 建立完成,他會通知Thread,然后 Thread 處理完數據后再返回給客戶端——這個過程是不阻塞的,這樣就能讓一個 Thread 處理更多的請求了。

RedisAutoConfiguration自動配置源碼分析

1、在SpringBoot的自動配置文件中,搜索redis可以找到對應的 Redis自動配置類

 

 2、RedisAutoConfiguration類的源碼

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class)
// 對應的引用配置文件 RedisProperties.class,所以說redis所有的配置可以在這里查看
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
    
       // 默認的是 RedisTemplate,他沒有過多的設置,其中的 Redis對象都是還需要序列化的!
    // 兩個泛型都是Object類型,我們之后使用需要強轉 <String, Object>
    // 所以@ConditionalOnMissingBean 表示我們可以自定義 RedisTemplate 來使用,那樣會更加方便
    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    // StringRedisTemplate,由於string類型是reids中最常用的類型,所以單獨提出來,方便開發人員調用
    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

}

配置文件

  • 可以在配置文件 以 spring.redis.xxx 來進行配置

 兩個API使用哪個?

  • 哪個好已經在上面說過了,lettuce支持高並發

  • 可以看到 源碼中,兩個方法都傳入了RedisConnectionFactory對象

public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)

進入這個接口可以看到有兩個實現類

 可以看到 JedisConnectionFactory中有很多類沒有生效

 可以看到 LettuceConnectionFactory是生效的

 所以在配置文件中配置時需要注意:SpringBoot 2.x以后 默認使用的lettuce,不要傻傻的配置到jedis了

測試

1、導入依賴

<!-- redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2、配置文件

# 配置 redis,不過默認配置就是本機,端口也是6379,這里為了看的清除
spring.redis.host=127.0.0.1
spring.redis.port=6379

3、測試連接

  • 在測試類中進行測試,可以直接注入 RedisTemplate 對象

package com.zxh;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

@SpringBootTest
class Redis02SpringbootApplicationTests {

    @Autowired
    RedisTemplate redisTemplate;

    @Test
    void contextLoads() {
        RedisConnectionFactory connectionFactory = redisTemplate.getConnectionFactory();
        RedisConnection connection = connectionFactory.getConnection();
        System.out.println(connection.ping());
    }

}

結果:

4、API測試

package com.zxh;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

@SpringBootTest
class Redis02SpringbootApplicationTests {

    @Autowired
    RedisTemplate redisTemplate;

    @Test
    void contextLoads() {
        /*
            redisTemplate:操作不同的數據類型,api和之前的命令都是一樣的
            opsForValue():操作字符串,類型String
            opsForSet
            opsForHash
            opsForZSet
            opsForGeo
            opsForHyperLogLog
         */
        // 除了進本的操作,我們常用的方法都可以直接通過redisTemplate操作,比如事務,和基本的 CRUD

        // 獲取redis的連接對象
        // RedisConnectionFactory connectionFactory = redisTemplate.getConnectionFactory();
        // RedisConnection connection = connectionFactory.getConnection();
        // System.out.println(connection.ping());

        redisTemplate.opsForValue().set("name", "zxh");
        System.out.println(redisTemplate.opsForValue().get("name"));
    }

}

結果:

自定義RestTemplate

為什么要自定義?

  • 首先RestTemplate 它沒有過多的配置

  • 默認的RestTemplate 使用的是jdk序列化,會有一些問題

關於序列化

  • 我們基於上面的測試,試一下存入的是中文的情況

1、測試

@SpringBootTest
class Redis02SpringbootApplicationTests {

    @Autowired
    RedisTemplate redisTemplate;

    @Test
    void contextLoads() {
        redisTemplate.opsForValue().set("name", "憤怒的張迅豪");
        System.out.println(redisTemplate.opsForValue().get("name"));
    }

}

結果:

 2、使用客戶端連接,發現已經被轉義過的

源碼分析的時候就說過了,所有的reids對象都需要進行序列化,而我們默認使用的RestTemplate的序列化,所以說是有問題的

3、源碼分析

我們可以看到源碼中,創建了默認的RedisTemplate

點進去可以看到,序列化設置都是null

 在構造器中,可以看到默認的序列化方式

自定義的RestTemplate

  • 開發通用模板,在公司拿過來直接用即可!

  • 還需要導入jackson依賴

<!-- jackson-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.10.2</version>
</dependency>

RedisConfig配置類

package com.zxh.config;

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.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration  // 配置類
public class RedisConfig {

    // 自定義RedisTemplate
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory){
        // 為了開發的方便,一般直接使用 <String, Object>
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory); // redis連接的線程安全工廠,源碼也是這樣配置的

        // Json序列化配置
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        //解決jackson2無法序列化LocalDateTime的問題,這里擴展一個LocalDateTime類型,它是日期類型對象 jdk1.8出的(並且這個類是不可變的和線程安全的,可以研究一下它的API),當然還需要對這個對象進行json格式的轉換,如下圖:
        om.disable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS);
        om.registerModule(new JavaTimeModule());
        
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // String 的序列化
         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;
    }

}

如果不配合使用,LocalDateTime類型放到Redis數據庫時,會變得很長一段,很難維護。

測試

控制台沒問題

 客戶端連接,命令行也可以顯示

 

 最后:在我們真實的開發中,或者你們在公司,一般都可以看到一個公司自己封裝RedisUtil

 

引用學習:https://space.bilibili.com/95256449/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM