作为一名开发者,在日常工作中,缓存是提升系统性能的关键手段之一,而 Redis 作为一款高性能的键值对数据库,在缓存领域占据着重要地位。今天,我就来和大家分享 Redis 的一些基础知识,从数据结构、通用命令,再到 Java 客户端的使用,带大家轻松入门 Redis

一、Redis 数据结构:多样类型,满足不同需求

Redis 是典型的 key - value 数据库,key 一般为 String 类型,而 value 类型丰富多样,可分为基本类型和特殊类型。

(一)基本类型

  • String:最基础的字符串类型,能存储普通的文本内容,比如 “hello world” 这样的简单字符串,是 Redis 中最常用的数据类型之一,可用于存储简单的键值对信息,像用户的昵称等。
  • Hash:类似 Java 中的 Map 结构,可存储一组键值对集合,例如 {name: "Jack", age: 21},非常适合存储对象类的数据,比如用户的个人信息,包含姓名、年龄等多个字段,方便对对象的各个属性进行操作。
  • List:有序列表,元素可以重复,且按照插入顺序排列,比如 [A -> B -> C -> C]。这种特性使得它很适合实现队列、栈等数据结构,比如消息队列场景,消息按顺序入队和出队。
  • Set:无序集合,元素具有唯一性,例如 {A, B, C}。基于这个特性,它可用于实现交集、并集等集合操作,比如统计两个用户群体的共同爱好。
  • SortedSet:有序集合,每个元素会关联一个分数(score),并按照分数进行排序,如 {A: 1, B: 2, C: 3}。在实际应用中,常用于排行榜等需要排序的场景,比如游戏玩家的积分排行榜。

(二)特殊类型

  • GEO:专门用于存储地理位置信息,像 {A: (120.3, 30.5)},可以实现附近地点查找等地理相关操作,例如外卖平台查找用户附近的商家。
  • BitMap:以位为单位进行操作,存储二进制数据,如 0110110101110101011。适合处理大量布尔型数据,比如用户的签到记录,用每一位表示用户某一天是否签到。
  • HyperLog:用于基数统计,能够高效地统计集合中不同元素的数量,基于二进制数据操作,在数据量很大时也能节省空间,比如统计网站的独立访客数量。

二、Redis 通用命令:便捷操作 Redis 数据

通用命令是部分数据类型都可以使用的指令,掌握这些命令能让我们更便捷地操作 Redis 数据。

  • KEYS:用于查看符合模板的所有 key。不过要注意,由于它会遍历所有 key,在生产环境有大量数据的情况下,会阻塞 Redis 服务器,所以不建议在生产环境使用。
  • DEL:删除指定的 key,能快速清理不需要的数据。
  • EXISTS:判断 key 是否存在,可用于检查数据是否存在于 Redis 中。
  • EXPIRE:为 key 设置有效期,当有效期到期时,该 key 会被自动删除,这对于实现缓存的自动失效非常有用。
  • TTL:查看一个 key 的剩余有效期,方便我们了解缓存还有多久失效。

如果想查看某个命令的具体用法,可以通过 help [command],比如 help keys,就能看到 KEYS pattern 等相关说明。

三、Redis 的 Java 客户端:让 Java 与 Redis 交互更简单

Java 连接 Redis 有多种客户端,下面介绍几种常用的:

  • Jedis:方法名和 Redis 命令基本一致,学习成本低,简单实用。但 Jedis 实例是线程不安全的,在多线程环境下需要基于连接池来使用。
  • Lettuce:基于 Netty 实现,支持同步、异步和响应式编程方式,并且是线程安全的。还支持 Redis 的哨兵模式、集群模式和管道模式,适用于对性能和并发要求较高的场景。
  • Redisson:是一个基于 Redis 实现的分布式、可伸缩的 Java 数据结构集合。包含了诸如 Map、Queue、Lock、Semaphore、AtomicLong 等强大功能,能很方便地实现分布式相关操作,比如分布式锁。

Jedis 连接池

由于 Jedis 本身线程不安全,且频繁创建和销毁连接会带来性能损耗,所以推荐大家使用 Jedis 连接池代替 Jedis 的直连方式。下面是一个简单的 Jedis 连接池示例代码:

public class JedisConnectionFactory {
    private static final JedisPool jedisPool;

    static {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        // 最大连接数
        jedisPoolConfig.setMaxTotal(8);
        // 最大空闲连接
        jedisPoolConfig.setMaxIdle(8);
        // 最小空闲连接
        jedisPoolConfig.setMinIdle(0);
        // 设置最长等待时间,单位 ms
        jedisPoolConfig.setMaxWaitMillis(200);
        jedisPool = new JedisPool(jedisPoolConfig, "192.168.150.101", 6379, 1000, "123321");
    }
    // 获取Jedis对象
    public static Jedis getJedis(){
        return jedisPool.getResource();
    }
}

通过连接池,我们可以在多线程环境下安全、高效地获取 Jedis 连接,避免了频繁创建和销毁连接的性能问题。

四、SpringDataRedis:Spring 家族的 Redis 工具

SpringDataRedis 中提供了 RedisTemplate 工具类,其中封装了各种对 Redis 的操作。并且将不同数据类型的操作 API 封装到了不同的类型中,比如:

  • redisTemplate.opsForValue():返回 ValueOperations,用于操作 String 类型数据。
  • redisTemplate.opsForHash():返回 HashOperations,用于操作 Hash 类型数据。
  • redisTemplate.opsForList():返回 ListOperations,用于操作 List 类型数据。
  • redisTemplate.opsForSet():返回 SetOperations,用于操作 Set 类型数据。
  • redisTemplate.opsForZSet():返回 ZSetOperations,用于操作 SortedSet 类型数据。
    同时,redisTemplate 本身也支持通用的命令。

使用时,我们可以通过 @Autowired 注入 RedisTemplate,然后编写测试代码来操作 Redis 数据,比如:

@SpringBootTest
public class RedisTest {
    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void testString() {
        // 插入一条string类型数据
        redisTemplate.opsForValue().set("name", "李四");
        // 读取一条string类型数据
        Object name = redisTemplate.opsForValue().get("name");
        System.out.println("name = " + name);
    }
}

SpringDataRedis 的序列化方式

在使用 SpringDataRedis 时,序列化方式很重要,它决定了数据在 Redis 中的存储形式以及读取时的解析方式。主要有以下两种方式:

(一)自定义 RedisTemplate 序列化(相对简单,不那么省空间)

我们可以自定义 RedisTemplate 的序列化方式,代码如下:

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
    // 创建Template
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    // 设置连接工厂
    redisTemplate.setConnectionFactory(redisConnectionFactory);
    // 设置序列化工
    GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
    // key和 hashKey采用 string序列化
    redisTemplate.setKeySerializer(RedisSerializer.string());
    redisTemplate.setHashKeySerializer(RedisSerializer.string());
    // value和 hashValue采用 JSON序列化
    redisTemplate.setValueSerializer(jsonRedisSerializer);
    redisTemplate.setHashValueSerializer(jsonRedisSerializer);
    return redisTemplate;
}

这种方式使用 JSON 序列化来处理 value 和 hashValue,使用起来相对简单,不需要手动进行序列化和反序列化操作,但由于存储的是 JSON 格式的数据,相对来说没有那么节省空间。

(二)使用 StringRedisTemplate(省空间,需手动序列化)

为了节省内存空间,我们可以使用 StringRedisTemplate。它的 key 和 value 的序列化方式默认就是 String 方式。当需要存储 Java 对象时,需要手动完成对象的序列化和反序列化。

例如,有一个 User 类:

public class User {
    private String name;
    private Integer age;

    // 构造方法、getter、setter等方法
}

存储和读取 User 对象的代码如下:

@Autowired
private StringRedisTemplate stringRedisTemplate;
// JSON工具
private static final ObjectMapper mapper = new ObjectMapper();

@Test
void testStringTemplate() throws JsonProcessingException {
    // 准备对象
    User user = new User("虎哥", 18);
    // 手动序列化
    String json = mapper.writeValueAsString(user);
    // 写入一条数据到redis
    stringRedisTemplate.opsForValue().set("user:200", json);

    // 读取数据
    String val = stringRedisTemplate.opsForValue().get("user:200");
    // 反序列化
    User user1 = mapper.readValue(val, User.class);
    System.out.println("user1 = " + user1);
}

这种方式因为统一使用 String 序列化器,只存储 String 类型的 key 和 value,所以比较节省空间,但需要手动进行对象的序列化和反序列化,相对麻烦一些。

以上就是 Redis 从数据结构、通用命令到 Java 客户端,以及 SpringDataRedis 序列化方式的相关知识。希望能帮助大家轻松入门 Redis,在实际开发中更好地运用它来提升系统性能。

更多推荐