redis 学习笔记

2020-03-01/2022-03-25

参考文档:

Spring Boot StringRedisTemplate常用操作

1. Redis 基础知识

  • Redis 是一款高性能的 NOSQL 系列的非关系型数据库。
  • NoSQL (Not Only SQL),意即“不仅仅是 SQL”,是一项全新的数据库理念,泛指非关系型的数据库。
  • NOSQL 和关系型数据库比较
  • 优点:
    • 成本:nosql 数据库简单易部署,基本都是开源软件,不需要像使用 Oracle 那样花费大量成本购买使用,相比关系型数据库价格便宜。
    • 查询速度:nosql 数据库将数据存储于缓存之中,关系型数据库将数据存储在硬盘中,自然查询速度远不及 nosql 数据库。
    • 存储数据的格式:nosql 的存储格式是 key,value 形式、文档形式、图片形式等等,所以可以存储基础类型以及对象或者是集合等各种格式,而数据库则只支持基础类型。
    • 扩展性:关系型数据库有类似 join 这样的多表查询机制的限制导致扩展很艰难。
  • 缺点:
    • 维护的工具和资料有限。
    • 不提供对 SQL 的支持,如果不支持 SQL 这样的工业标准,将产生一定用户的学习和使用成本。
    • 不提供关系型数据库对事务的处理。
  • 非关系型数据库的优势:
    • 性能 NOSQL 是基于键值对的,可以想象成表中的主键和值的对应关系,而且不需要经过 SQL 层的解析,所以性能非常高。
    • 可扩展性同样也是因为基于键值对,数据之间没有耦合性,所以非常容易水平扩展。
  • 关系型数据库的优势:
    • 复杂查询可以用 SQL 语句方便的在一个表以及多个表之间做非常复杂的数据查询。
    • 事务支持使得对于安全性能很高的数据访问要求得以实现。对于这两类数据库,对方的优势就是自己的弱势,反之亦然。
  • 总结:关系型数据库与 NoSQL 数据库并非对立而是互补的关系,即通常情况下使用关系型数据库,在适合使用 NoSQL 的时候使用 NoSQL 数据库,让 NoSQL 数据库对关系型数据库的不足进行弥补。一般会将数据存储在关系型数据库中,在 NoSQL 数据库中备份存储关系型数据库的数据。
  • Redis 是用 C 语言开发的一个开源的高性能键值对(key-value)数据库,官方提供测试数据,50 个并发执行 100000 个请求,读的速度是 110000 次/s,写的速度是 81000 次/s ,且 Redis 通过提供多种键值数据类型来适应不同场景下的存储需求,目前为止 Redis 支持的键值数据类型如下:
    • 字符串类型 string
    • 哈希类型 hash
    • 列表类型 list
    • 集合类型 set
    • 有序集合类型 sortedset
  • Redis 的应用场景
    • 缓存(数据查询、短连接、新闻内容、商品内容等等)
    • 聊天室的在线好友列表
    • 任务队列。(秒杀、抢购、12306 等等)
    • 应用排行榜
    • 网站访问统计
    • 数据过期处理(可以精确到毫秒)
    • 分布式集群架构中的 session 分离

2. 主流的 NOSQL 产品

  • 键值(Key-Value)存储数据库
    • 相关产品: Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB
    • 典型应用: 内容缓存,主要用于处理大量数据的高访问负载。
    • 数据模型: 一系列键值对
    • 优势: 快速查询
    • 劣势: 存储的数据缺少结构化
  • 列存储数据库
    • 相关产品:Cassandra, HBase, Riak
    • 典型应用:分布式的文件系统
    • 数据模型:以列簇式存储,将同一列数据存在一起
    • 优势:查找速度快,可扩展性强,更容易进行分布式扩展
    • 劣势:功能相对局限
  • 文档型数据库
    • 相关产品:CouchDB、MongoDB
    • 典型应用:Web 应用(与 Key-Value 类似,Value 是结构化的)
    • 数据模型: 一系列键值对
    • 优势:数据结构要求不严格
    • 劣势: 查询性能不高,而且缺乏统一的查询语法
  • 图形(Graph)数据库
    • 相关数据库:Neo4J、InfoGrid、Infinite Graph
    • 典型应用:社交网络
    • 数据模型:图结构
    • 优势:利用图结构相关算法。
    • 劣势:需要对整个图做计算才能得出结果,不容易做分布式的集群方案。

3. Redis 命令操作

  • Redis 存储的是:key,value 格式的数据,其中 key 都是字符串,value 有 5 种不同的数据结构

    • 字符串类型 string
    • 哈希类型 hash:map 格式
    • 列表类型 list:linkedlist 格式。支持重复元素
    • 集合类型 set:不允许重复元素
    • 有序集合类型 sortedset:不允许重复元素,且元素有顺序

  • 字符串类型 string

    • 存储:set key value
      • set username zhangsan
    • 拉取:get key
      • get username
    • 删除:del key
      • del username
  • 哈希类型 hash

    • 存储:hset key field value
      • hset myhash username lisi
      • hset myhash password 123
    • 获取:
      • hget key field: 获取指定的 field 对应的值
        • hget myhash username
      • hgetall key:获取所有的 field 和 value
        • hgetall myhash
    • 删除 hash 中值:hdel key field [field...]
      • hdel myhash username
    • 删除整个 hash:del key
      • del myhash
  • 列表类型:list:可以添加一个元素到列表的头部(左边)或者尾部(右边)

    • 存储:
      • lpush key value [value...]:将元素加入列表左表
        • lpush myList a
      • rpush key value [value...]:将元素加入列表右边
        • rpush myList c
    • 获取:
      • lrange key start end:范围获取
        • lrange myList 0 -1 代表获取所有
    • 删除
      • lpop key: 删除列表最左边的元素,并将元素返回
      • rpop key: 删除列表最右边的元素,并将元素返回
  • 集合类型 set : 不允许重复元素

    • 存储:sadd key member [member...]
    • 获取:smembers key:获取 set 集合中所有元素
    • 删除:srem key member [member...]:删除 set 集合中的某个元素
  • 有序集合类型 sortedset:不允许重复元素,且元素有顺序。每个元素都会关联一个 double 类型的分数。Redis 正是通过分数来为集合中的成员进行从小到大的排序。

    • 存储:zadd key score member [score member...]
    • 获取:zrange key start end [withscores] withscores 代表是否包含分数
    • 删除:zrem key member
  • 通用命令

    • keys *:查询所有的键
    • type key:获取键对应的 value 的类型
    • del key [key...]:删除指定的 key 和所对应的 value

4. Redis 持久化

  • Redis 是一个内存数据库,当 Redis 服务器重启,获取电脑重启,数据会丢失,我们可以将 Redis 内存中的数据持久化保存到硬盘的文件中。
  • RDB 持久化机制:默认方式,不需要进行配置,默认就使用这种机制
    • 在一定的间隔时间中,检测 key 的变化情况,然后持久化数据
    • 在 redis.windwos.conf 文件中进行配置
    • 1#  900秒内,如果至少1个keys发生改变,则持久化一次
      2save 900 1
      3#  300秒内,如果至少10个keys发生改变,则持久化一次
      4save 300 10
      5#  60秒内,如果至少10000个keys发生改变,则持久化一次
      6save 60 10000
      
    • 修改完配置以后,重启服务器。redis-server.exe redis.windows.conf 表示有某个配置文件启动服务器。
  • AOF:日志记录的方式,可以记录每一条命令的操作。可以每一次命令操作后,持久化数据,效率低。
    • 配置文件 redis.windwos.conf
      1appendonly no(关闭aof) --> appendonly yes (开启aof)
      2# appendfsync always : 每一次操作都进行持久化
      3appendfsync everysec : 每隔一秒进行一次持久化
      4# appendfsync no	 : 不进行持久化
      

5. Java 客户端:Jedis

  • Jedis: 一款 Java 操作 Redis 数据库的工具。
  • 使用步骤:
    1//1. 获取连接
    2//如果不传参数,默认为localhost和6379端口
    3Jedis jedis = new Jedis("localhost",6379);
    4//2. 操作
    5jedis.set("username","zhangsan");
    6//3. 关闭连接
    7jedis.close();
    
  • 操作 string 类型
    • String set(String key, String value); 返回 OK
    • String get(String key); 返回 value
    • String setex(String key,int seconds,String value); 设置键值对并指定过期时间,返回 OK
  • 操作 hash 类型
    • Long hset(String key,String field,String value); 返回成功了几行
    • String hget(String key,String field); 返回 value
    • Map<String,String> hgetall(String key);
    • Long hdel(String key,String... fields); 返回成功了几行
  • 操作 list 类型
    • Long lpush/rpush(String key,String strings);
    • String lpop/rpop(String key);
    • List<String> lrange(String key,long start,long end);
  • 操作 set 类型
    • Long sadd(String key,String... members);
    • Set<String> smembers(String key); 获取所有值
    • Long srem(String key,String... members);
  • 操作 sortedset 类型
    • Long zadd(String key,double score,String member);
    • Set<String> zrange(String key,long begin,long end);
    • Long zrem(String key,String... members);
  • Jedis 连接池:JedisPool
    •  1//0.创建一个配置对象(可省略)
       2JedisPoolConfig config = new JedisPoolConfig();
       3config.setMaxTotal(50);
       4config.setMaxIdle(10);
       5
       6//1.创建Jedis连接池对象
       7JedisPool jedisPool = new JedisPool(config,"localhost",6379);
       8//2.获取连接
       9Jedis jedis = jedisPool.getResource();
      10//3. 使用
      11jedis.set("hehe","heihei");
      12//4. 关闭 归还到连接池中
      13jedis.close();
      
    • JedisPoolUtils
       1package pers.ylq.util;
       2
       3import redis.clients.jedis.Jedis;
       4import redis.clients.jedis.JedisPool;
       5import redis.clients.jedis.JedisPoolConfig;
       6
       7import java.io.IOException;
       8import java.io.InputStream;
       9import java.util.Properties;
      10
      11/**
      12 JedisPool工具类
      13    加载配置文件,配置连接池的参数
      14    提供获取连接的方法
      15 */
      16public class JedisPoolUtils {
      17
      18    private static JedisPool jedisPool;
      19
      20    static{
      21        //读取配置文件
      22        InputStream is = JedisPoolUtils.class.getClassLoader().getResourceAsStream("jedis.properties");
      23        //创建Properties对象
      24        Properties pro = new Properties();
      25        //关联文件
      26        try {
      27            pro.load(is);
      28        } catch (IOException e) {
      29            e.printStackTrace();
      30        }
      31        //获取数据,设置到JedisPoolConfig中
      32        JedisPoolConfig config = new JedisPoolConfig();
      33        config.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal")));
      34        config.setMaxIdle(Integer.parseInt(pro.getProperty("maxIdle")));
      35
      36        //初始化JedisPool
      37        jedisPool = new JedisPool(config,pro.getProperty("host"),Integer.parseInt(pro.getProperty("port")));
      38    }
      39
      40    /**
      41     * 获取连接方法
      42     */
      43    public static Jedis getJedis(){
      44        return jedisPool.getResource();
      45    }
      46}
      

6. Redis 使用样例

  •  1public class ProvinceServiceImpl implements ProvinceService {
     2    //声明dao
     3    private ProvinceDao dao = new ProvinceDaoImpl();
     4    /**
     5        使用redis缓存
     6     */
     7    @Override
     8    public String findAllJson() {
     9        //1.先从redis中查询数据
    10        //1.1获取redis客户端连接
    11        Jedis jedis = JedisPoolUtils.getJedis();
    12        String province_json = jedis.get("province");
    13        //2判断 province_json 数据是否为null
    14        if(province_json == null || province_json.length() == 0){
    15            //redis中没有数据
    16            System.out.println("redis中没数据,查询数据库...");
    17            //2.1从数据中查询
    18            List<Province> ps = dao.findAll();
    19            //2.2将list序列化为json
    20            ObjectMapper mapper = new ObjectMapper();
    21            try {
    22                province_json = mapper.writeValueAsString(ps);
    23            } catch (JsonProcessingException e) {
    24                e.printStackTrace();
    25            }
    26            //2.3 将json数据存入redis
    27            jedis.set("province",province_json);
    28            //归还连接
    29            jedis.close();
    30        }else{
    31            System.out.println("redis中有数据,查询缓存...");
    32        }
    33        return province_json;
    34    }
    35}
    

7. StringRedisTemplate

我们在 spring boot 中集成 redis

Redis 文档中介绍存入或查询可以使 Object 类型,但是实际中用的是 String 类型

POM 依赖

1<!--redis依赖配置-->
2<dependency>
3  <groupId>org.springframework.boot</groupId>
4  <artifactId>spring-boot-starter-data-redis</artifactId>
5</dependency>

配置

 1spring:
 2  redis:
 3    host: localhost  # Redis服务器地址
 4    database: 0 # Redis数据库索引(默认为0)
 5    port: 6379 # Redis服务器连接端口
 6    password: # Redis服务器连接密码(默认为空)
 7    jedis:
 8      pool:
 9        max-active: 8 # 连接池最大连接数(使用负值表示没有限制)
10        max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
11        max-idle: 8 # 连接池中的最大空闲连接
12        min-idle: 0 # 连接池中的最小空闲连接
13    timeout: 3000ms # 连接超时时间(毫秒)

注入对象

1@Autowired
2StringRedisTemplate stringRedisTemplate;

Redis Value

 1@Test
 2public void valueAddResitTest(){
 3    stringRedisTemplate.opsForValue().set("key","value");
 4}
 5
 6@Test
 7public void valueGetResitTest(){
 8    String value = stringRedisTemplate.opsForValue().get("key");
 9    logger.info("value:{}", value);
10}
11
12@Test
13public void valueDelResitTest(){
14    stringRedisTemplate.delete("key");
15}
16
17@Test
18public void valueTimeoutResitTest(){
19    stringRedisTemplate.opsForValue().set("timeStep", new Date().getTime()+"", 2 ,TimeUnit.MINUTES);
20}

Redis List

 1// list数据类型适合于消息队列的场景:比如12306并发量太高,而同一时间段内只能处理指定数量的数据!必须满足先进先出的原则,其余数据处于等待
 2@Test
 3public void listPushResitTest(){
 4    // leftPush依次由右边添加
 5    stringRedisTemplate.opsForList().rightPush("myList","1");
 6    stringRedisTemplate.opsForList().rightPush("myList","2");
 7    stringRedisTemplate.opsForList().rightPush("myList", "A");
 8    stringRedisTemplate.opsForList().rightPush("myList", "B");
 9    // leftPush依次由左边添加
10    stringRedisTemplate.opsForList().leftPush("myList", "0");
11}
12
13@Test
14public void listGetListResitTest(){
15    // 查询类别所有元素
16    List<String> listAll = stringRedisTemplate.opsForList().range( "myList", 0, -1);
17    logger.info("list all {}", listAll);
18    // 查询前3个元素
19    List<String> list = stringRedisTemplate.opsForList().range( "myList", 0, 3);
20    logger.info("list limit {}", list);
21}
22
23@Test
24public void listRemoveOneResitTest(){
25    // 删除先进入的B元素
26    stringRedisTemplate.opsForList().remove("myList",1, "B");
27}
28
29@Test
30public void listRemoveAllResitTest(){
31    // 删除所有A元素
32    stringRedisTemplate.opsForList().remove("myList",0, "A");
33}

Redis Hash

 1@Test
 2public void hashPutResitTest(){
 3    // map的key值相同,后添加的覆盖原有的
 4    stringRedisTemplate.opsForHash().put("banks:12600000", "a", "b");
 5}
 6
 7@Test
 8public void hashGetEntiresResitTest(){
 9    // 获取map对象
10    Map<Object, Object> map = stringRedisTemplate.opsForHash().entries("banks:12600000");
11    logger.info("objects:{}", map);
12}
13
14@Test
15public void hashGeDeleteResitTest(){
16    // 根据map的key删除这个元素
17    stringRedisTemplate.opsForHash().delete("banks:12600000", "c");
18}
19
20@Test
21public void hashGetKeysResitTest(){
22    // 获得map的key集合
23    Set<Object> objects =  stringRedisTemplate.opsForHash().keys("banks:12600000");
24    logger.info("objects:{}", objects);
25}
26
27@Test
28public void hashGetValueListResitTest(){
29    // 获得map的value列表
30    List<Object> objects = stringRedisTemplate.opsForHash().values("banks:12600000");
31    logger.info("objects:{}", objects);
32}
33
34@Test
35public void hashSize() {
36    // 获取map对象大小
37    long size =  stringRedisTemplate.opsForHash().size("banks:12600000");
38    logger.info("size:{}", size);
39}

8. SpringBoot 整合 redis

参考文献:mall整合Redis实现缓存功能

pom 依赖和 redis 配置参考 StringRedisTemplate

添加 Redis 的自定义 key 配置

1# 自定义redis key
2redis:
3  key:
4    prefix:
5      authCode: "portal:authCode:"
6    expire:
7      authCode: 120 # 验证码超期时间

添加 RedisService 接口用于定义一些常用 Redis 操作

 1package com.macro.mall.tiny.service;
 2
 3/**
 4 * redis操作Service,
 5 * 对象和数组都以json形式进行存储
 6 * Created by macro on 2018/8/7.
 7 */
 8public interface RedisService {
 9    /**
10     * 存储数据
11     */
12    void set(String key, String value);
13
14    /**
15     * 获取数据
16     */
17    String get(String key);
18
19    /**
20     * 设置超期时间
21     */
22    boolean expire(String key, long expire);
23
24    /**
25     * 删除数据
26     */
27    void remove(String key);
28
29    /**
30     * 自增操作
31     * @param delta 自增步长
32     */
33    Long increment(String key, long delta);
34
35}

注入 StringRedisTemplate,实现 RedisService 接口

 1package com.macro.mall.tiny.service.impl;
 2
 3import com.macro.mall.tiny.service.RedisService;
 4import org.springframework.beans.factory.annotation.Autowired;
 5import org.springframework.data.redis.core.StringRedisTemplate;
 6import org.springframework.stereotype.Service;
 7
 8import java.util.concurrent.TimeUnit;
 9
10/**
11 * redis操作Service的实现类
12 * Created by macro on 2018/8/7.
13 */
14@Service
15public class RedisServiceImpl implements RedisService {
16    @Autowired
17    private StringRedisTemplate stringRedisTemplate;
18
19    @Override
20    public void set(String key, String value) {
21        stringRedisTemplate.opsForValue().set(key, value);
22    }
23
24    @Override
25    public String get(String key) {
26        return stringRedisTemplate.opsForValue().get(key);
27    }
28
29    @Override
30    public boolean expire(String key, long expire) {
31        return stringRedisTemplate.expire(key, expire, TimeUnit.SECONDS);
32    }
33
34    @Override
35    public void remove(String key) {
36        stringRedisTemplate.delete(key);
37    }
38
39    @Override
40    public Long increment(String key, long delta) {
41        return stringRedisTemplate.opsForValue().increment(key,delta);
42    }
43}

然后在 Controller 调用即可

9. Spring Data Redis

参考文献:Spring Data Redis 最佳实践!

Spring Data Redis 是Spring 框架提供的用于操作Redis的方式

9.1 Spring Cache 操作 redis

当Spring Boot 结合Redis来作为缓存使用时,最简单的方式就是使用Spring Cache了,使用它我们无需知道Spring中对Redis的各种操作,仅仅通过它提供的@Cacheable 、@CachePut 、@CacheEvict 、@EnableCaching等注解就可以实现缓存功能。

9.1.1 常用注解

@EnableCaching

开启缓存功能,一般放在启动类上。

@Cacheable

使用该注解的方法当缓存存在时,会从缓存中获取数据而不执行方法,当缓存不存在时,会执行方法并把返回结果存入缓存中。一般使用在查询方法上,可以设置如下属性:

  • value:缓存名称(必填),指定缓存的命名空间;
  • key:用于设置在命名空间中的缓存key值,可以使用SpEL表达式定义;
  • unless:条件符合则不缓存;
  • condition:条件符合则缓存。

其实在数据库中存储的是一个 hash 类型,比如

1@Cacheable(value = "myvalue", key = "#param")
2public Integer methodB(String param) {
3    return 111;
4}
5// 则存储的 key 为 myvalue::param
6
7@Cacheable("myvalue")
8// 若缺失 key, 则缺省按照方法的所有参数进行组合

@CachePut

使用该注解的方法每次执行时都会把返回结果存入缓存中。一般使用在新增方法上,可以设置如下属性:

  • value:缓存名称(必填),指定缓存的命名空间;
  • key:用于设置在命名空间中的缓存key值,可以使用SpEL表达式定义;
  • unless:条件符合则不缓存;
  • condition:条件符合则缓存。

@CacheEvict

使用该注解的方法执行时会清空指定的缓存。一般使用在更新或删除方法上,可以设置如下属性:

  • value:缓存名称(必填),指定缓存的命名空间;
  • key:用于设置在命名空间中的缓存key值,可以使用SpEL表达式定义;
  • condition:条件符合则缓存。
9.1.2 使用步骤

添加依赖

1<!--redis依赖配置-->
2<dependency>
3    <groupId>org.springframework.boot</groupId>
4    <artifactId>spring-boot-starter-data-redis</artifactId>
5</dependency>

配置 redis

1spring:
2  redis:
3    host: 192.168.6.139 # Redis服务器地址
4    database: 0 # Redis数据库索引(默认为0)
5    port: 6379 # Redis服务器连接端口
6    password: # Redis服务器连接密码(默认为空)
7    timeout: 1000ms # 连接超时时间

添加配置类

此时我们就会想到有没有什么办法让 Redis 中存储的数据变成标准的 JSON 格式,然后可以设置一定的过期时间,不设置过期时间容易产生很多不必要的缓存数据。

我们可以通过给 RedisTemplate 设置 JSON 格式的序列化器,并通过配置 RedisCacheConfiguration 设置超时时间来实现以上需求,具体配置类 RedisConfig 代码如下;

 1/**
 2 * Redis配置类
 3 * Created by macro on 2020/3/2.
 4 */
 5@EnableCaching
 6@Configuration
 7public class RedisConfig extends CachingConfigurerSupport {
 8
 9    /**
10     * redis数据库自定义key
11     */
12    public  static final String REDIS_KEY_DATABASE="mall";
13
14    @Bean
15    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
16        RedisSerializer<Object> serializer = redisSerializer();
17        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
18        redisTemplate.setConnectionFactory(redisConnectionFactory);
19        redisTemplate.setKeySerializer(new StringRedisSerializer());
20        redisTemplate.setValueSerializer(serializer);
21        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
22        redisTemplate.setHashValueSerializer(serializer);
23        redisTemplate.afterPropertiesSet();
24        return redisTemplate;
25    }
26
27    @Bean
28    public RedisSerializer<Object> redisSerializer() {
29        //创建JSON序列化器
30        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
31        ObjectMapper objectMapper = new ObjectMapper();
32        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
33        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
34        serializer.setObjectMapper(objectMapper);
35        return serializer;
36    }
37
38    @Bean
39    public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
40        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
41        //设置Redis缓存有效期为1天
42        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
43                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer())).entryTtl(Duration.ofDays(1));
44        return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
45    }
46
47}

Service 类

 1@Service
 2public class PmsBrandServiceImpl implements PmsBrandService {
 3    @Autowired
 4    private PmsBrandMapper brandMapper;
 5
 6    @CacheEvict(value = RedisConfig.REDIS_KEY_DATABASE, key = "'pms:brand:'+#id")
 7    @Override
 8    public int update(Long id, PmsBrand brand) {
 9        brand.setId(id);
10        return brandMapper.updateByPrimaryKeySelective(brand);
11    }
12
13    @CacheEvict(value = RedisConfig.REDIS_KEY_DATABASE, key = "'pms:brand:'+#id")
14    @Override
15    public int delete(Long id) {
16        return brandMapper.deleteByPrimaryKey(id);
17    }
18
19    @Cacheable(value = RedisConfig.REDIS_KEY_DATABASE, key = "'pms:brand:'+#id", unless = "#result==null")
20    @Override
21    public PmsBrand getItem(Long id) {
22        return brandMapper.selectByPrimaryKey(id);
23    }
24
25}

9.2 redis 连接池

Lettuce 是一种可伸缩,线程安全,完全非阻塞的 Redis 客户端,多个线程可以共享一个 RedisConnection,它利用 Netty NIO 框架来高效地管理多个连接,从而提供了异步和同步数据访问方式,用于构建非阻塞的反应性应用程序。

导入依赖

1<dependency>
2    <groupId>org.apache.commons</groupId>
3    <artifactId>commons-pool2</artifactId>
4</dependency>

配置文件

1spring:
2  redis:
3    lettuce:
4      pool:
5        max-active: 8 # 连接池最大连接数
6        max-idle: 8 # 连接池最大空闲连接数
7        min-idle: 0 # 连接池最小空闲连接数
8        max-wait: -1ms # 连接池最大阻塞等待时间,负值表示没有限制

9.3 RedisTemplate

Spring Cache 给我们提供了操作 Redis 缓存的便捷方法,但是也有很多局限性。比如说我们想单独设置一个缓存值的有效期怎么办?我们并不想缓存方法的返回值,我们想缓存方法中产生的中间值怎么办?此时我们就需要用到 RedisTemplate 这个类了,接下来我们来讲下如何通过 RedisTemplate 来自由操作 Redis 中的缓存。

RedisService

  1/**
  2 * redis 操作 Service
  3 */
  4public interface RedisService {
  5
  6    /**
  7     * 保存属性
  8     */
  9    void set(String key, Object value, long time);
 10
 11    /**
 12     * 保存属性
 13     */
 14    void set(String key, Object value);
 15
 16    /**
 17     * 获取属性
 18     */
 19    Object get(String key);
 20
 21    /**
 22     * 删除属性
 23     */
 24    Boolean del(String key);
 25
 26    /**
 27     * 批量删除属性
 28     */
 29    Long del(List<String> keys);
 30
 31    /**
 32     * 设置过期时间
 33     */
 34    Boolean expire(String key, long time);
 35
 36    /**
 37     * 获取过期时间
 38     */
 39    Long getExpire(String key);
 40
 41    /**
 42     * 判断是否有该属性
 43     */
 44    Boolean hasKey(String key);
 45
 46    /**
 47     * 按delta递增
 48     */
 49    Long incr(String key, long delta);
 50
 51    /**
 52     * 按delta递减
 53     */
 54    Long decr(String key, long delta);
 55
 56    /**
 57     * 获取Hash结构中的属性
 58     */
 59    Object hGet(String key, String hashKey);
 60
 61    /**
 62     * 向Hash结构中放入一个属性
 63     */
 64    Boolean hSet(String key, String hashKey, Object value, long time);
 65
 66    /**
 67     * 向Hash结构中放入一个属性
 68     */
 69    void hSet(String key, String hashKey, Object value);
 70
 71    /**
 72     * 直接获取整个Hash结构
 73     */
 74    Map<Object, Object> hGetAll(String key);
 75
 76    /**
 77     * 直接设置整个Hash结构
 78     */
 79    Boolean hSetAll(String key, Map<String, Object> map, long time);
 80
 81    /**
 82     * 直接设置整个Hash结构
 83     */
 84    void hSetAll(String key, Map<String, Object> map);
 85
 86    /**
 87     * 删除Hash结构中的属性
 88     */
 89    void hDel(String key, Object... hashKey);
 90
 91    /**
 92     * 判断Hash结构中是否有该属性
 93     */
 94    Boolean hHasKey(String key, String hashKey);
 95
 96    /**
 97     * Hash结构中属性递增
 98     */
 99    Long hIncr(String key, String hashKey, Long delta);
100
101    /**
102     * Hash结构中属性递减
103     */
104    Long hDecr(String key, String hashKey, Long delta);
105
106    /**
107     * 获取Set结构
108     */
109    Set<Object> sMembers(String key);
110
111    /**
112     * 向Set结构中添加属性
113     */
114    Long sAdd(String key, Object... values);
115
116    /**
117     * 向Set结构中添加属性
118     */
119    Long sAdd(String key, long time, Object... values);
120
121    /**
122     * 是否为Set中的属性
123     */
124    Boolean sIsMember(String key, Object value);
125
126    /**
127     * 获取Set结构的长度
128     */
129    Long sSize(String key);
130
131    /**
132     * 删除Set结构中的属性
133     */
134    Long sRemove(String key, Object... values);
135
136    /**
137     * 获取List结构中的属性
138     */
139    List<Object> lRange(String key, long start, long end);
140
141    /**
142     * 获取List结构的长度
143     */
144    Long lSize(String key);
145
146    /**
147     * 根据索引获取List中的属性
148     */
149    Object lIndex(String key, long index);
150
151    /**
152     * 向List结构中添加属性
153     */
154    Long lPush(String key, Object value);
155
156    /**
157     * 向List结构中添加属性
158     */
159    Long lPush(String key, Object value, long time);
160
161    /**
162     * 向List结构中批量添加属性
163     */
164    Long lPushAll(String key, Object... values);
165
166    /**
167     * 向List结构中批量添加属性
168     */
169    Long lPushAll(String key, Long time, Object... values);
170
171    /**
172     * 从List结构中移除属性
173     */
174    Long lRemove(String key, long count, Object value);
175}

RedisServiceImpl

  1/**
  2 * redis操作实现类
  3 */
  4@Service
  5public class RedisServiceImpl implements RedisService {
  6    @Autowired
  7    private RedisTemplate<String, Object> redisTemplate;
  8
  9    @Override
 10    public void set(String key, Object value, long time) {
 11        redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
 12    }
 13
 14    @Override
 15    public void set(String key, Object value) {
 16        redisTemplate.opsForValue().set(key, value);
 17    }
 18
 19    @Override
 20    public Object get(String key) {
 21        return redisTemplate.opsForValue().get(key);
 22    }
 23
 24    @Override
 25    public Boolean del(String key) {
 26        return redisTemplate.delete(key);
 27    }
 28
 29    @Override
 30    public Long del(List<String> keys) {
 31        return redisTemplate.delete(keys);
 32    }
 33
 34    @Override
 35    public Boolean expire(String key, long time) {
 36        return redisTemplate.expire(key, time, TimeUnit.SECONDS);
 37    }
 38
 39    @Override
 40    public Long getExpire(String key) {
 41        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
 42    }
 43
 44    @Override
 45    public Boolean hasKey(String key) {
 46        return redisTemplate.hasKey(key);
 47    }
 48
 49    @Override
 50    public Long incr(String key, long delta) {
 51        return redisTemplate.opsForValue().increment(key, delta);
 52    }
 53
 54    @Override
 55    public Long decr(String key, long delta) {
 56        return redisTemplate.opsForValue().increment(key, -delta);
 57    }
 58
 59    @Override
 60    public Object hGet(String key, String hashKey) {
 61        return redisTemplate.opsForHash().get(key, hashKey);
 62    }
 63
 64    @Override
 65    public Boolean hSet(String key, String hashKey, Object value, long time) {
 66        redisTemplate.opsForHash().put(key, hashKey, value);
 67        return expire(key, time);
 68    }
 69
 70    @Override
 71    public void hSet(String key, String hashKey, Object value) {
 72        redisTemplate.opsForHash().put(key, hashKey, value);
 73    }
 74
 75    @Override
 76    public Map<Object, Object> hGetAll(String key) {
 77        return redisTemplate.opsForHash().entries(key);
 78    }
 79
 80    @Override
 81    public Boolean hSetAll(String key, Map<String, Object> map, long time) {
 82        redisTemplate.opsForHash().putAll(key, map);
 83        return expire(key, time);
 84    }
 85
 86    @Override
 87    public void hSetAll(String key, Map<String, Object> map) {
 88        redisTemplate.opsForHash().putAll(key, map);
 89    }
 90
 91    @Override
 92    public void hDel(String key, Object... hashKey) {
 93        redisTemplate.opsForHash().delete(key, hashKey);
 94    }
 95
 96    @Override
 97    public Boolean hHasKey(String key, String hashKey) {
 98        return redisTemplate.opsForHash().hasKey(key, hashKey);
 99    }
100
101    @Override
102    public Long hIncr(String key, String hashKey, Long delta) {
103        return redisTemplate.opsForHash().increment(key, hashKey, delta);
104    }
105
106    @Override
107    public Long hDecr(String key, String hashKey, Long delta) {
108        return redisTemplate.opsForHash().increment(key, hashKey, -delta);
109    }
110
111    @Override
112    public Set<Object> sMembers(String key) {
113        return redisTemplate.opsForSet().members(key);
114    }
115
116    @Override
117    public Long sAdd(String key, Object... values) {
118        return redisTemplate.opsForSet().add(key, values);
119    }
120
121    @Override
122    public Long sAdd(String key, long time, Object... values) {
123        Long count = redisTemplate.opsForSet().add(key, values);
124        expire(key, time);
125        return count;
126    }
127
128    @Override
129    public Boolean sIsMember(String key, Object value) {
130        return redisTemplate.opsForSet().isMember(key, value);
131    }
132
133    @Override
134    public Long sSize(String key) {
135        return redisTemplate.opsForSet().size(key);
136    }
137
138    @Override
139    public Long sRemove(String key, Object... values) {
140        return redisTemplate.opsForSet().remove(key, values);
141    }
142
143    @Override
144    public List<Object> lRange(String key, long start, long end) {
145        return redisTemplate.opsForList().range(key, start, end);
146    }
147
148    @Override
149    public Long lSize(String key) {
150        return redisTemplate.opsForList().size(key);
151    }
152
153    @Override
154    public Object lIndex(String key, long index) {
155        return redisTemplate.opsForList().index(key, index);
156    }
157
158    @Override
159    public Long lPush(String key, Object value) {
160        return redisTemplate.opsForList().rightPush(key, value);
161    }
162
163    @Override
164    public Long lPush(String key, Object value, long time) {
165        Long index = redisTemplate.opsForList().rightPush(key, value);
166        expire(key, time);
167        return index;
168    }
169
170    @Override
171    public Long lPushAll(String key, Object... values) {
172        return redisTemplate.opsForList().rightPushAll(key, values);
173    }
174
175    @Override
176    public Long lPushAll(String key, Long time, Object... values) {
177        Long count = redisTemplate.opsForList().rightPushAll(key, values);
178        expire(key, time);
179        return count;
180    }
181
182    @Override
183    public Long lRemove(String key, long count, Object value) {
184        return redisTemplate.opsForList().remove(key, count, value);
185    }
186}

标题:redis 学习笔记
作者:Rainsheep
地址:HTTPS://www.rainsheep.cn/articles/2020/03/01/1582997924952.html

评论
发表评论
       
       
取消