整合redis-笔记

77 阅读4分钟

介绍redis

Redis是一个开源的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息代理。一般主要使用五大数据类型:字符串(Strings)、列表(Lists)、集合(Sets)、有序集合(Sorted sets)和哈希表(Hashes)。redis还有其它数据结构,如:位图(Bitmaps)、超日志(HyperLogLogs)和地理空间索引半径查询(Geospatial indexes with radius queries)。

特性和使用情况就不过多叙述了

SpringBoot整合redis

导包

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

配置

redis:
  # Redis服务器地址
  host: localhost
  # Redis服务器端口号
  port: 6379
  # 使用的数据库索引,默认是0
  database: 0
  # 连接超时时间
  timeout: 1800000
  # 设置密码 默认空
  password: "" 
  lettuce:
    pool:
      # 最大阻塞等待时间,负数表示没有限制
      max-wait: -1
      # 连接池中的最大空闲连接
      max-idle: 5
      # 连接池中的最小空闲连接
      min-idle: 0
      # 连接池中最大连接数,负数表示没有限制
      max-active: 20

模板类 StringRedisTemplate和RedisTemplate

StringRedisTemplate和RedisTemplate都是Spring Data Redis提供的用于操作Redis的模板类。它们都提供了一系列的方法来操作Redis,例如opsForValue()、opsForList()、opsForSet()等。

RedistTemplate自定义序列化

为什么要自定义序列化?

  1. 效率低:Java的序列化效率相对较低,如果你需要存储大量的数据,或者需要频繁地读写数据,使用Java的序列化可能会成为性能瓶颈。
  2. 数据不易阅读:Java的序列化结果是二进制数据,这使得在Redis客户端查看数据时很不方便。
  3. 不支持跨语言:Java的序列化结果只有Java应用才能理解,如果你的Redis需要被其他语言的应用访问,这种序列化方式就不适合。

不使用自定义序列化也可以在java类实现Serializable接口,会被RedisTemplate的默认序列化器JdkSerializationRedisSerializer序列化。或者可显式地配置序列化器,如下代码:

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        // 创建模板
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        // 设置连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // 设置GenericJackson2JsonRedisSerializer序列化工具
        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;
    }
}

使用RedisTemplate

每种方法的简单例子如下:

public class RedisExample {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // String
    public void stringExample() {
        // 插入
        redisTemplate.opsForValue().set("stringKey", "stringValue");
        // 查询
        Object value = redisTemplate.opsForValue().get("stringKey");
        System.out.println("String value: " + value);
    }

    // List
    public void listExample() {
        // 插入
        redisTemplate.opsForList().rightPush("listKey", "listValue1");
        redisTemplate.opsForList().rightPush("listKey", "listValue2");
        // 查询
        List<Object> list = redisTemplate.opsForList().range("listKey", 0, -1);
        System.out.println("List value: " + list);
    }

    // Set
    public void setExample() {
        // 插入
        redisTemplate.opsForSet().add("setKey", "setValue1", "setValue2");
        // 查询
        Set<Object> set = redisTemplate.opsForSet().members("setKey");
        System.out.println("Set value: " + set);
    }

    // Hash
    public void hashExample() {
        // 插入
        redisTemplate.opsForHash().put("hashKey", "field1", "hashValue1");
        redisTemplate.opsForHash().put("hashKey", "field2", "hashValue2");
        // 查询
        Object hashValue1 = redisTemplate.opsForHash().get("hashKey", "field1");
        Object hashValue2 = redisTemplate.opsForHash().get("hashKey", "field2");
        System.out.println("Hash value1: " + hashValue1);
        System.out.println("Hash value2: " + hashValue2);
    }

    // ZSet
    public void zsetExample() {
        // 插入
        redisTemplate.opsForZSet().add("zsetKey", "zsetValue1", 1);
        redisTemplate.opsForZSet().add("zsetKey", "zsetValue2", 2);
        // 查询
        Set<Object> zset = redisTemplate.opsForZSet().range("zsetKey", 0, -1);
        System.out.println("ZSet value: " + zset);
    }
}

redis每种数据类型的使用场景

  1. String(字符串):这是最简单的类型,可以存储字符串、整数或浮点数。常用于存储单个值,如配置项、计数器、验证码、会话数据等。
  2. List(列表):这是一个字符串列表,按插入顺序排序。常用于实现队列(通过LPUSH/RPOP或RPUSH/LPOP命令)、堆栈(通过LPUSH/LPOP命令)、最近使用列表等。
  3. Set(集合):这是一个无序的字符串集合。常用于存储无序的唯一元素,如标签、好友关系等。
  4. Hash(哈希):这是一个键值对集合,适用于存储对象。常用于存储、读取、修改对象属性。
  5. ZSet(有序集合):这是一个字符串集合,每个元素都关联着一个浮点数分数,元素按分数排序。常用于实现排行榜、带权重的队列等。

以下是使用Redis的五种数据类型(String、List、Set、Hash、ZSet)在特定场景中的使用示例:

  1. String(字符串):存储登录凭证
@Autowired
private StringRedisTemplate stringRedisTemplate;

public void storeLoginToken(String userId, String token) {
    stringRedisTemplate.opsForValue().set("loginToken:" + userId, token);
}

public String getLoginToken(String userId) {
    return stringRedisTemplate.opsForValue().get("loginToken:" + userId);
}
  1. List(列表):实现一个简单的消息队列
@Autowired
private RedisTemplate<String, Object> redisTemplate;

public void enqueueMessage(String message) {
    redisTemplate.opsForList().rightPush("messageQueue", message);
}

public Object dequeueMessage() {
    return redisTemplate.opsForList().leftPop("messageQueue");
}
  1. Set(集合):存储用户的标签
@Autowired
private RedisTemplate<String, Object> redisTemplate;

public void addUserTag(String userId, String tag) {
    redisTemplate.opsForSet().add("userTags:" + userId, tag);
}

public Set<Object> getUserTags(String userId) {
    return redisTemplate.opsForSet().members("userTags:" + userId);
}
  1. Hash(哈希):存储用户的属性
@Autowired
private RedisTemplate<String, Object> redisTemplate;

public void setUserAttribute(String userId, String attribute, String value) {
    redisTemplate.opsForHash().put("user:" + userId, attribute, value);
}

public Object getUserAttribute(String userId, String attribute) {
    return redisTemplate.opsForHash().get("user:" + userId, attribute);
}
  1. ZSet(有序集合):实现一个排行榜
@Autowired
private RedisTemplate<String, Object> redisTemplate;

public void addUserScore(String userId, double score) {
    redisTemplate.opsForZSet().add("leaderboard", userId, score);
}

public Set<Object> getTopUsers(int topN) {
    return redisTemplate.opsForZSet().reverseRange("leaderboard", 0, topN - 1);
}

6.简单分布式锁

public class RedisLock {

    private final StringRedisTemplate redisTemplate;

    public RedisLock(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 获取锁
     * @param key 锁的key
     * @param timeout 锁的超时时间
     * @return 是否获取成功
     */
    public boolean lock(String key, long timeout) {
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        Boolean success = ops.setIfAbsent(key, "lock", timeout, TimeUnit.SECONDS);
        return success != null && success;
    }

    /**
     * 释放锁
     * @param key 锁的key
     */
    public void unlock(String key) {
        redisTemplate.delete(key);
    }
}