(代码篇)java, spring整合redis最详解析

底层原理

通过代码与redis服务器进行交互的原理是,
TCP网络传输协议,
和mysql一样,我们可以通过代码编写redis指令,
然后通过网络请求传给redis服务器程序执行,
并且通过网络接收响应回来的结果

部署redis服务端

redis程序目前只支持在linux系统上运行
我们可以在centos或ubuntu虚拟机上,使用docker进行部署

docker run -p 6379:6379 -it redis:latest

Jedis

jedis,即java redis,是redis服务器的客户端,是用户通过代码实现与redis服务器进行交互的途径

方法参数返回结果功能
connect()void连接到 Redis 服务器。
disconnect()void断开与 Redis 服务器的连接。
ping()字符串 “PONG” 表示连接正常检测与 Redis 服务器的连接状态。
set(String, String)String keyString value字符串 “OK” 表示设置成功设置指定 key 的值为给定的字符串。
get(String)String key指定 key 的值,如果 key 不存在,则返回 null获取指定 key 的值。
del(String...)可变参数 String... keys删除的 key 的数量删除一个或多个 key。
exists(String)String key如果 key 存在,则返回 true,否则返回 false检查给定 key 是否存在。
expire(String, int)String keyint seconds如果设置成功,则返回 1;如果 key 不存在或设置失败,则返回 0设置指定 key 的过期时间,单位为秒。
ttl(String)String key指定 key 的剩余过期时间(单位:秒),-1 表示永不过期,-2 表示 key 不存在获取指定 key 的剩余过期时间。
hset(String, String, String)String keyString fieldString value如果 field 是一个新的字段,并成功设置了值,则返回 true;如果 field 已经存在,旧值将被新值覆盖,返回 false为哈希表中的字段赋值。
hget(String, String)String keyString field指定字段的值,如果 key 或者 field 不存在,则返回 null获取哈希表中指定字段的值。
hdel(String, String...)String key,可变参数 String... fields删除的字段的数量删除哈希表中的一个或多个字段。
hexists(String, String)String keyString field如果哈希表中存在给定字段,则返回 true,否则返回 false检查哈希表中是否存在给定字段。
hgetAll(String)String key哈希表中所有字段-值对的 Map 集合,如果 key 不存在,则返回空的 Map获取哈希表中所有字段的值。
zadd(String, double, String)String keydouble scoreString member如果 member 成员是一个新的成员,并成功添加,则返回 true;如果 member 已经是集合中的成员,只是更新对应的 score 值,则返回 false将一个 member 元素及其 score 值加入到有序集合中。
zrange(String, long, long)String keylong startlong end有序集合指定区间内的成员列表返回有序集合中指定区间内的成员,按 score 值递增排序。
zrem(String, String...)String key,可变参数 String... members移除的成员的数量移除有序集合中的一个或多个成员。
zcard(String)String key有序集合的基数(集合中的成员数量)获取有序集合的成员数量。

首先,引入依赖

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

然后,就是建立连接
因为,jedis本身并不是线程安全的,所以需要为每一个线程单独建立一个连接,这就需要用到连接池了

Jedis连接池

用到的api有:

  1. JedisPoolConfig:用于封装连接池的配置项参数
  2. JedisPool:连接池对象
public class JedisConnectionFactory {

    private static final JedisPool pool;

    static {
        JedisPoolConfig config = new JedisPoolConfig();
        //最多创建连接数
        config.setMaxTotal(8);
        //空闲池最大连接数
        config.setMaxIdle(8);
        //空闲池最少拥有连接
        config.setMinIdle(0);
        //等待时间
        config.setMaxWaitMillis(200L);

        //根据配置参数创建连接池
        pool = new JedisPool(config, "192.168.59.136", 6379,
                1000, "1234");
    }

    /**
    * 获取连接
    * */
    public static Jedis getConnection(){
        return pool.getResource();
    }

}

连接池做了什么事情呢
我们可以从连接池通过getResource,获得一个jedis对象,这与我们直接创建的jedis对象不同的是,从连接池获得的jedis对象多了一个不为null的DataSource对象,其实就是连接池对象,因此当我们调用jedis.close时不会销毁连接,而是将连接归还到连接池中
源码部分如下
当我们调用pool.getResource时,就自动为jedis对象设置了DataSource属性

  public Jedis getResource() {
    Jedis jedis = super.getResource();
    jedis.setDataSource(this);
    return jedis;
  }
  protected void setDataSource(Pool<Jedis> jedisPool) {
    this.dataSource = jedisPool;
  }

  @Override
  public void close() {
    if (dataSource != null) {
      Pool<Jedis> pool = this.dataSource;
      this.dataSource = null;
      if (isBroken()) {
        pool.returnBrokenResource(this);
      } else {
        pool.returnResource(this);
      }
    } else {
      connection.close();
    }
  }

SpringDataRedis

核心api是RedisTemplate ,是spring的一个模板类,底层仍是基于jedis

RedisTemplate

调api很简单,直接通过自动注入的redisTemplate对象去调就行了
需要注意,这里将操作根据不同的redis数据类型进行了分类,我们要先通过redisTemplate的方法获得对应数据类型的对象,才能执行相关的操作

方法参数返回结果功能
opsForValue()ValueOperations<K, V>对象获取用于操作字符串类型数据的 ValueOperations 对象
opsForList()ListOperations<K, V>对象获取用于操作列表类型数据的 ListOperations 对象
opsForSet()SetOperations<K, V>对象获取用于操作集合类型数据的 SetOperations 对象
opsForZSet()ZSetOperations<K, V>对象获取用于操作有序集合类型数据的 ZSetOperations 对象
opsForHash()HashOperations<K, HK, HV>对象获取用于操作哈希类型数据的 HashOperations 对象
boundValueOps()K keyBoundValueOperations<K, V>对象获取指定 key 的绑定操作对象,用于对该 key 进行操作
boundListOps()K keyBoundListOperations<K, V>对象获取指定 key 的列表绑定操作对象,用于对该列表进行操作
boundSetOps()K keyBoundSetOperations<K, V>对象获取指定 key 的集合绑定操作对象,用于对该集合进行操作
boundZSetOps()K keyBoundZSetOperations<K, V>对象获取指定 key 的有序集合绑定操作对象,用于对该有序集合进行操作
boundHashOps()K keyBoundHashOperations<K, HK, HV>对象获取指定 key 的哈希绑定操作对象,用于对该哈希进行操作
execute(RedisCallback<T> action)RedisCallback<T> action根据 RedisCallback 的泛型参数 T 的返回值类型执行 Redis 命令,并通过 RedisCallback 回调函数处理返回结果
execute(RedisScript<T> script, List<K> keys, Object... args)RedisScript<T> script, List<K> keys, Object... args根据 RedisScript 的泛型参数 T 的返回值类型执行 Lua 脚本,并传入参数进行处理

相关依赖

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>3.2.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.12.0</version>
</dependency>



其中,spring-boot-starter-data-redis是一个依赖组,包括三个子依赖
在这里插入图片描述

配置文件

springData将配置信息从代码中分离,单独写在application.yml文件中,项目启动后,程序会自动读取配置信息

spring:
  data:
    redis:
      host: 192.168.59.136
      port: 6379
      password: 1234
      lettuce:
        pool:
          max-active: 8
          max-idle: 8
          min-idle: 0
          max-wait: 100

序列化器

众所周知,计算机只能识别0101这样的二进制数据,无法识别人类语言中的字符,所以数据在保存之前,是先要依据字符集以及编码格式,编码成二进制数据,这就是所谓的序列化
redisTemplate可以接收复杂的java对象作为value值存到redis中,前提是需要先将java对象编码成二进制数据
接下来,将详细分析集中序列化方案

序列化方案

redisTemplate中支持的序列化器都实现了RedisSerializer接口
推荐使用第二个方式,占用内存最小,速度也最快,也就是先把对象转json字符串,再转字节数组
反序列化时,就先将字节数组转json字符串,再转java对象

序列化器接收参数实现细节功能优点缺点
JdkSerializationRedisSerializer待序列化/反序列化的对象使用 JDK 自带的序列化方式将对象序列化为字节流将 Java 对象序列化为字节数组,将字节数组反序列化为对象原生自带,无需要引入第三方,默认使用k,v都被序列成字节数组,查询出来是16进制,看不懂
StringRedisSerializer待序列化/反序列化的对象将对象序列化为字符串形式存储在 Redis 中将字符串对象转换为字节数组,将字节数组转换为字符串对象占用空间小,性能高专门处理string类型
GenericJackson2JsonRedisSerializer待序列化/反序列化的对象使用 Jackson 库将对象序列化为 JSON 格式将对象序列化为 JSON 字符串,将 JSON 字符串反序列化为对象适用于所有类型的对象性能差,速度慢,序列化后的数据较大 ,自动加上了全类名字段

可以创建一个配置类来设置redisTemplate对象的序列化方式

@Configuration
public class RedisTemplateConfig {
    
    @Bean 
    public RedisTemplate<String,Object> redisTemplateConfig(RedisConnectionFactory factory)throws Exception{
        
        
        //创建redisTemplate对象
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        //设置连接
        template.setConnectionFactory(factory);
        //设置序列化器
        GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
        
        template.setKeySerializer(serializer);
        template.setHashKeySerializer(serializer);
        
        template.setValueSerializer(serializer);
        template.setHashValueSerializer(serializer);
        
        return template;
    }
    
}

StringRedisTemplate

默认采用string序列化,需要手动将java对象序列化
其实很简单,相信大家也都用过FastJson序列化和反序列化,和以前一样的用法

@SpringBootTest(classes = Application.class)
public class TestRedisTemplate {

    @Autowired
    StringRedisTemplate template;

    @Test
    public void testStringSerial(){

        //手动序列化对象
        User user = new User(1,"zs", "123");

        String json = JSONObject.toJSONString(user);

        //存入redis
        ValueOperations<String, String> opsForValue = template.opsForValue();
        opsForValue.set("user"+":"+user.getUserId(),json);

    }

}

效果如图
在这里插入图片描述
对于value是对象的,我们还可以使用Hash作为数据类型,将字段和值进行分离,方便进行对数据进行精细化操作

@SpringBootTest(classes = Application.class)
public class TestRedisTemplate {

    @Autowired
    StringRedisTemplate template;

    @Test
    public void testStringSerial()throws Exception{

        //手动序列化对象
        User user = new User(1,"zs", "123");

        String json = JSONObject.toJSONString(user);

        //存入redis
        Class<? extends User> clazz = user.getClass();
        HashOperations<String, Object, Object> hashOperations = template.opsForHash();
        String key = "user" + ":" + user.getUserId();

        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true);
            hashOperations.put("user",field.getName(),field.get(user).toString());
        }

    }

}

效果
在这里插入图片描述

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值