侧边栏壁纸
博主头像
suringYu

走走停停

  • 累计撰写 62 篇文章
  • 累计创建 20 个标签
  • 累计收到 13 条评论

目 录CONTENT

文章目录

在java中使用redis

suringYu
2022-04-02 / 0 评论 / 0 点赞 / 765 阅读 / 7,847 字

一、redis客户端类型

类型优缺点
jedis以Redis命令作为方法名称,学习成本低,简单实用。但是]edis实例是线程不安全的,多线程环境下需要基于连接池来使用
lettuceLettuce是基于Netty实现的,支持同步、异步和响应式编程方式,并且是线程安全的。支持Redis的哨兵模式、集群模式和管道模式。Spring默认支持此类型
redissonRedisson是一个底层基于Redis实现的分布式、可伸缩的Java数据结构集合。包含了诸如Map、Queue、Lock、semaphore、AtomicLong等强大功能(本文中未做介绍)

springDateRedis 集成了jedis和lettuce

二、使用教程

1、jedis

jedis仓库地址:https://github.com/redis/jedis

首先创建一个maven工程,使用依赖

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>4.1.1</version>
</dependency>

建立连接

    void setUp() {
        // 1、建立连接
        jedis = new Jedis("127.0.0.1", 6379);
        // 2、设置密码
        jedis.auth("123456");
        // 3、选择库
        jedis.select(0);
    }

操作redis

 	@Test
    void testString() {
        String set = jedis.set("name", "lisa");
        System.out.println(set);
        String name = jedis.get("name");
        System.out.println(name);
    }

    @Test
    void testHash() {
        // 插入数据
        jedis.hset("user:1","name","jack");
        jedis.hset("user:1","age","18");
        // 获取
        Map<String, String> map = jedis.hgetAll("user:1");
        System.out.println(map);
    }
    void tearDown() {
        if (jedis != null){
            jedis.close();
        }
    }

测试完整代码

package com.jedisTest;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;

import java.util.Map;

public class JedisTest {
    
    private Jedis jedis;

    @BeforeEach
    void setUp() {
        // 1、建立连接
        jedis = new Jedis("", 6379);
        // 2、设置密码
        jedis.auth("123456");
        // 3、选择库
        jedis.select(0);
    }

    @Test
    void testString() {
        String set = jedis.set("name", "lisa");
        System.out.println(set);
        String name = jedis.get("name");
        System.out.println(name);
    }

    @Test
    void testHash() {
        // 插入数据
        jedis.hset("user:1","name","jack");
        jedis.hset("user:1","age","18");
        // 获取
        Map<String, String> map = jedis.hgetAll("user:1");
        System.out.println(map);
    }

    @AfterEach
    void tearDown() {
        // 逻辑健壮性处理,结束后关闭连接,没有成功连接则不处理
        if (jedis != null){
            jedis.close();
        }
    }
}

总结

jedis最大优势就是调用方法名称和命令行名称一致,建议结合redis常用命令食用,也就不做过多演示

2、Spring Data Redis

2.1 介绍

SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis,访问官网

q10ATP.png

  • 提供了对不同Redis客户端的整合( Lettuce和Jedis)
  • 提供了RedisTemplate统一API来操作Redis
  • 支持Redis的发布订阅模型
  • 支持Redis哨兵和Redis集群
  • 支持基于Lettuce的响应式编程
  • 支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化
  • 支持基于Redis的JDKCollection实现

SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中,不同的数据对象使用不同的API避免臃肿的调用方法

q106fO.png

2.2 使用方法

首先创建一个springboot工程,引入依赖

       <!-- Spring Data Redis 依赖 -->
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
		<!-- 连接池依赖 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

添加配置

spring.redis.host= 127.0.0.1
spring.redis.port= 6379
spring.redis.password= 123456
spring.redis.lettuce.pool.max-active= 8
spring.redis.lettuce.pool.max-wait= 100ms
spring.redis.lettuce.pool.max-idle= 8
spring.redis.lettuce.pool.min-idle= 0 

定义一个用户类用来测试

public class User {

    private String name;
    private int age;

    public User(){

    }

    public User(String name, int age){
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

代码调用,具体调用方法不做演示了,按照数据类型分类的命令

package com.heima.redisdemo;

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.core.RedisTemplate;

@SpringBootTest
class RedisDemoApplicationTests {
    @Autowired
    private RedisTemplate redisTemplate;
    @Test
    void contextLoads() {
        redisTemplate.opsForValue().set("name","jerry");
        redisTemplate.opsForHash().put("man","name","jok");
        Boolean aBoolean = redisTemplate.opsForHash().hasKey("man", "name");
        System.out.println(aBoolean);
    }
    @Test
    void obj(){
        User user = new User("tom",20);
        redisTemplate.opsForValue().set("user:2",user);
        User u = (User) redisTemplate.opsForValue().get("user:2");
        System.out.println(u);
	}
}

RedisTemplate可以接收任意Object作为值写入Redis,只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化,得到的结果是这样的:

q1fJtH.png

缺点:

  • 可读性差
  • 内存占用较大

但是这个是可以解决的,通过springDataRedis的序列化方式自定义解决

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        // 创建RedisTemplate对象
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        // 设置连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // 创建JSON序列化工具
        GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        // 设置key的序列化
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setHashKeySerializer(RedisSerializer.string());
        // 设置value的序列化
        redisTemplate.setValueSerializer(jsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jsonRedisSerializer);
        return redisTemplate;
    }
}

注意需要依赖

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

再次运行上面代码的效果

qIqYDJ.png

此时对象类数据会有多的数据字段@class,这个字段是序列化工具用来自动完成反序列化的,也就是下面这句代码需要用到的

qIxLa4.png

User u = (User) redisTemplate.opsForValue().get("user:2");

Spring默认提供了一个StringRedisTemplate类(经典白学之前的内容😂),它的key和value的序列化方式默认就是String方式。省去了我们自定义RedisTemplate的过程:

@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
void contextLoads() {
    stringRedisTemplate.opsForValue().set("name","jerry");
    stringRedisTemplate.opsForHash().put("man","name","jok");
    Boolean aBoolean = stringRedisTemplate.opsForHash().hasKey("man", "name");
    System.out.println(aBoolean);
}

直接使用就可以,需要注意的是:使用StringRedisTemplate不能自动序列化与反序列化对象,需要手动序列化与反序列化,也就是下面这样

@Test
void doObj(){
    User user = new User("mark", 18);
    String s = JSONObject.toJSONString(user);
    stringRedisTemplate.opsForValue().set("user:1",s);
    String jsonUser = stringRedisTemplate.opsForValue().get("user:1");
    User parse = JSONObject.parseObject(jsonUser, User.class);
    System.out.println(parse);
}

最终结果是

qIxOIJ.png

qoS80O.png

总结

Spring Data Redis 在spring中使用更方法,兼容性也更好,需要注意的是springDataRedis的序列化方式自定义处理,当业务数据量比较大的时候,序列化存储对象中的@class占用内存量可能会非常多,建议使用StringRedisTemplate手动序列化而不是自动序列化

0

评论区