Redis快速入门与应用

一、Redis概述

Redis是用C语言开发的一个开源的高性能基于内存运行的键值对NoSQL数据库,相比于必须按照规定格式存储的关系型数据库而言,非关系型数据库的数据格式更灵活,通常用于查大规模数据的存储。

Redis就是非关系型数据库的一种,它基于内存,数据结构是k-v形式的。主要作用于缓存。Redis是单线程的,在多用户并发操作情况下,它是按序处理完一个再处理另一个请求。可以实现数据持久化和主从复制,除了基本的k-v结构外也支持更复杂的结构。只要开启Master-Slave策略就能够实现数据备份。它的并发能力能达到六七万。

在高并发场景下如果要经常不断查MySQL数据库来取出相同的数据,重复连续的读写操作导致磁盘IO过高,并发能力差。但通过Redis缓存下较为频繁使用的数据后,请求将直接查询Redis里的数据,减少数据库负载,达到有效地提高程序响应速度的目的。

二、Redis的下载和安装

Windows安装: https://github.com/dmajkic/redis/releases
官网:
中文官网:http://redis.cn/topics/introduction
英文官网:http://redis.io/topics/introduction
​ redis-benchmark.exe 测试性能
​ redis-check-aof.exe 测试持久化
​ redis-cli.exe 客户端
​ redis-server.exe 服务端

三、Redis启动

  1. redis默认不是后台启动的,修改这个.conf文件
    开启守护进程:223行
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
daemonize no   #no改成yes即可开启守护进程   daemonize yes
  1. 启动redis服务,指定启动的conf文件
redis-server XXX/redis.conf 
  1. 使用redis-cli 进行连接
redis-cli -p 6379
  1. 查看redis的进程是否开启
ps -ef|grep redis

可见pid为41164
Redis相关知识:

(1)Redis默认拥有16个数据库,数据库编号从0开始,默认使用0号数据库。conf配置文件可修改数量。
在这里插入图片描述
(2)使用select 数据库编号 可以切换使用的数据库

(3)dbsize 命令查看当前数据库key的数量

(4)keys * 命令查看当前数据库所有的key

(5)flushdb 命令清空当前数据库

(6)flushall 命令清空所有数据库

(7)Redis中所有数据库使用同一个密码。默认没有密码,Redis认为安全层面应该由Linux来保证

(8)Redis中所有索引都是从0开始

(9)Redis默认端口是6379

四、Redis五大数据类型及操作

    1. redis的数据结构:
        redis存储的是:key,value格式的数据。
        其中key都是字符串,value有5种不同的数据结构
        value的数据结构:
                1) 字符串类型 string
                2) 哈希类型 hash : map格式 
                3) 列表类型 list : linkedlist格式。支持重复元素
                4) 集合类型 set  : 不允许重复元素
                5) 有序集合类型 sortedset:不允许重复元素,且元素有顺序

    2. 字符串类型 string
        1. 存储: set key value
            127.0.0.1:6379> set username zhangsan
            OK
        2. 获取: get key
            127.0.0.1:6379> get username
            "zhangsan"
        3. 删除: del key
            127.0.0.1:6379> del age
            (integer) 1
    3. 哈希类型 hash
        1. 存储: hset key field value
            127.0.0.1:6379> hset myhash username lisi
            (integer) 1
            127.0.0.1:6379> hset myhash password 123
            (integer) 1
        2. 获取:
            * hget key field: 获取指定的field对应的值
                127.0.0.1:6379> hget myhash username
                "lisi"
            * hgetall key:获取所有的field和value
                127.0.0.1:6379> hgetall myhash
                1) "username"
                2) "lisi"
                3) "password"
                4) "123"

        3. 删除: hdel key field
            127.0.0.1:6379> hdel myhash username
            (integer) 1

    4. 列表类型 list:
    可以添加一个元素到列表的头部(左边)或者尾部(右边)
        1. 添加:
            1. lpush key value: 将元素加入列表左表

            2. rpush key value:将元素加入列表右边

                127.0.0.1:6379> lpush myList a
                (integer) 1
                127.0.0.1:6379> lpush myList b
                (integer) 2
                127.0.0.1:6379> rpush myList c
                (integer) 3
        2. 获取:
            * lrange key start end :范围获取
                127.0.0.1:6379> lrange myList 0 -1
                1) "b"
                2) "a"
                3) "c"
        3. 删除:
            * lpop key: 删除列表最左边的元素,并将元素返回
            * rpop key: 删除列表最右边的元素,并将元素返回
            * lrem key count value : 删除key下count数量的value元素
        4. 获取个数:
            * llen key: 获取元素个数
            		 
    6. 集合类型 set : 不允许重复元素
        1. 存储:sadd key value
            127.0.0.1:6379> sadd myset a
            (integer) 1
            127.0.0.1:6379> sadd myset a
            (integer) 0
        2. 获取:smembers key:获取set集合中所有元素
            127.0.0.1:6379> smembers myset
            1) "a"
        3. 删除:srem key value:删除set集合中的某个元素   
            127.0.0.1:6379> srem myset a
            (integer) 1
        4. 获取个数:
            * scard key: 获取元素个数              
              
    7. 有序集合类型 sortedset:
    【ps:不允许重复元素,且元素有顺序.
    每个元素都会关联一个double类型的分数。
    redis正是通过分数来为集合中的成员进行从小到大的排序。】

        1. 存储:zadd key score value
            127.0.0.1:6379> zadd mysort 60 zhangsan
            (integer) 1
            127.0.0.1:6379> zadd mysort 50 lisi
            (integer) 1
            127.0.0.1:6379> zadd mysort 80 wangwu
            (integer) 1
        2. 获取:zrange key start end [withscores]
            127.0.0.1:6379> zrange mysort 0 -1
            1) "lisi"
            2) "zhangsan"
            3) "wangwu"

            127.0.0.1:6379> zrange mysort 0 -1 withscores
            1) "zhangsan"
            2) "60"
            3) "wangwu"
            4) "80"
            5) "lisi"
            6) "500"
        3. 删除:zrem key value
            127.0.0.1:6379> zrem mysort lisi
            (integer) 1
        4. 获取个数:
            * zcard key: 获取元素个数     
            
    8. 通用命令
        1. keys * : 查询所有的键
        2. type key : 获取键对应的value的类型
        3. del key:删除指定的key value

五、Redis持久化

redis是内存数据库,如果没有持久化,那么数据宕机即失。

持久化概念:利用磁盘等将数据进行保存,在特定的时间将保存的数据进行恢复的工作机制称为持久化。

持久化的两种方式:

(1) 快照

将某个时间点的工作状态保存下来,恢复时可直接恢复指定时间点的工作状态。Redis中这种方式称为RDB。

修改内存中数据保存的文件的名称,默认名为dump.rdb
在这里插入图片描述
rdb保存目录
在这里插入图片描述
<1>使用bgsave命令保存kv到.rdb文件:

此命令可以手动保存,并让该保存操作在后台执行,redis服务可以继续执行其之后的指令,使用较多。

bgsave指令工作原理:
在这里插入图片描述
<2>配置自动保存 (修改配置文件后需要重启Redis)
在这里插入图片描述
conf文件中,以“save 900 1”为说明,900s内发现一个key变化(指增删改),Linux则fork()一个进程去保存k-v值在dump.db中。

RDB缺点:
(1) 基于快照思想,每次读写都是全部数据,当数据量较大时,效率非常低
(2) 基于fork创建子进程,内存产生额外的消耗
(3) 宕机带来数据丢失风险(可能某个时间点的数据未保存)

(2) 日志

把对数据的所有 操作的命令 记录下来,恢复数据时 重新执行 这些命令。Redis中这种方式称为AOF。

appendonly no  #默认是不开启aof模式的,默认是使用rdb方式持久化的,在大部分所有的情况下,rdb完全够用! 改为yes开启aof功能
appendfilename "appendonly.aof"  # 持久化的文件的名字

# appendfsync always  # 每次修改都会 sync 消耗性能
appendfsync everysec  # 每秒执行一次 sync,可能会丢失这一秒的数据
# appendfsync no      # 不执行 sync 操作系统自己同步数据,速度最快,但一般也不用。

在这里插入图片描述
如上图:
只许追加文件但不可以改写文件,故而文件会越来越大。如果这个aof文件大于64M。fork一个新的进程来将文件进行重写。
redis启动之初会读取该文件重新构建数据,根据日志文件的内容将写指令从前到后执行一次,以完成数据的恢复工作(是大数据就很慢)。

如果aof文件有错误,redis会启动不起来的,需要修复aof文件,redis 提供了一个工具 redis-check-aof --fix

模拟aof出错并修复的步骤:
1.shutdown exit,退出redis
2.删除datas/dump.rdb文件,因为里面有保存数据
3.vim appendonly.aof,肆意修改,并保存
4.尝试启动redis,登录cli的时候报错:
Could not connect to Redis at node1:6379: Connection refused
5.执行修复工具:redis-check-aof --fix …/datas/appendonly.aof
6.需要你确认,输入y,修复成功。Successfully truncated AOF
7.再次执行,如果aof文件正常,就会发现数据都恢复了

【ps:破坏aof文件,在aof文件底部添加数据是可以修复的,但是如果set k1 v1这种的结构破坏了,aof也无法修复,修复了直接是空的数据库。】

官方使用的建议:
通常,要想提供很高的数据保障性,那么建议同时使用两种持久化方式。 如果可以接受灾难带来的几分钟的数据丢失,可以仅使用RDB。 很多用户仅使用了AOF,但是我们建议,既然RDB可以时不时的给数据做个完整的快照,并且提供更快的重启,所以最好还是也使用RDB。

六、redis客户端Jedis和Luttuce

Lettuce 和 Jedis 都是Redis的客户端,客户端连接 Redis 使用的是 TCP协议,可以直接连接redis server。

(1)Jedis

Jedis在实现上是直接连接的redis server,在多线程环境下是非线程安全的,此时使用 连接池 ,为每个Jedis实例增加物理连接。

客户端连接 Redis 使用的是 TCP协议,直连的方式每次需要建立 TCP连接,而 连接池 的方式是可以预先初始化好客户端连接,所以每次只需要从 连接池借用即可,而借用和归还操作是在本地进行的,只有少量的并发同步开销,远远小于新建TCP连接的开销。另外,直连的方式无法限制 redis客户端对象的个数,在极端情况下可能会造成连接泄漏,而连接池的形式可以有效的保护和控制资源的使用。

(2)Lettuce

Lettuce的连接是基于Netty的,连接实例StatefulRedisConnection,可以在多个线程间并发访问。因为StatefulRedisConnection是线程安全的,所以一个连接实例(即StatefulRedisConnection)就可以满足多线程环境下的并发访问,这个是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。lettuce主要利用netty实现与redis的同步和异步通信

七、使用springboot整合redis客户端:Jedis和Luttuce

使用springboot连接redis的时候,在springboot1.X版本默认使用的是Jedis,但是在springboot2.X版本默认使用Lettuce。
【ps:无论用什么客户端,向redis中存储对象都必须要序列化

(1)SpringBoot2.X集成Lettuce连接池:

<1>依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <!--lettuce pool連接池-->
            <artifactId>commons-pool2</artifactId>
        </dependency>

<2> application.properties配置文件

spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=root
# 连接池最大连接数(使用负值表示没有限制) 默认为8
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认为-1
spring.redis.lettuce.pool.max-wait=-1ms
# 连接池中的最大空闲连接 默认为8
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接 默认为 0
spring.redis.lettuce.pool.min-idle=0

<3>配置redis配置类,自定义 RedisTemplate:

自定义 RedisTemplate ,设置序列化器,方便操作实例对象

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.io.Serializable;

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Serializable> redisTemplate(LettuceConnectionFactory connectionFactory) {
        RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setConnectionFactory(connectionFactory);
        return redisTemplate;
    }
}

<4>定义测试实体类

public class User implements Serializable {
    private static final long serialVersionUID = 4220515347228129741L;
    private Integer id;
    private String username;
 
    public User(Integer id, String username) {
        this.id = id;
        this.username = username;
    }
 
    public User() {
    }
    //getter/setter 省略
}

<5>测试

//@RunWith(SpringRunner.class)表示运行在spring环境下。这时@Aurowried将能注入RedisTemplate
@RunWith(SpringRunner.class)  
@SpringBootTest
public class RedisTest {
    private Logger logger = LoggerFactory.getLogger(RedisTest.class);
    @Autowired
    private RedisTemplate<String, Serializable> redisTemplate;
 
    @Test
    public void test() {
        String key = "user:1"; //层级命名,根据业务场景定义
        redisTemplate.opsForValue().set(key, new User(1,"花满楼"));
        User user = (User) redisTemplate.opsForValue().get(key);
        logger.info("uesr: "+user.toString());
    }
}

(2)SpringBoot2.X整合Jedis:

因为 springboot2.0中“默认”是使用 Lettuce来集成Redis服务,spring-boot-starter-data-redis默认只引入了 Lettuce包,并没有引入 jedis包支持。所以需要手动引入 jedis的包,并排除掉 lettuce的包
<1>依赖配置:

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-redis</artifactId>
     <exclusions>
        <exclusion>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>

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

<2>application.properties配置,使用jedis的连接池

spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=root
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.max-wait=-1ms
spring.redis.jedis.pool.min-idle=0
spring.redis.jedis.pool.max-active=8

<3>配置redis配置类,自定义 RedisTemplate,Jedis的template使用的连接对象是 JedisConnectionFactory,需要手动配置并注JedisConnectionFactory。
springboot2.x集成Jedis并不会读取配置文件中的 spring.redis.host等此类配置,需要手动给Factory设置值。

@Configuration
public class RedisConfig2 {
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.password}")
    private String password;
    
    @Bean
    public JedisConnectionFactory jedisConnectionFactory() {
    //在 springboot 2.x版本中推荐使用 RedisStandaloneConfiguration类来设置连接的端口,地址等属性。
    //因为JedisConnectionFactory设置连接的方法已过时
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
        //手动设置值
        config.setHostName(host);
        config.setPort(port);
        config.setPassword(RedisPassword.of(password));
        JedisConnectionFactory connectionFactory = new JedisConnectionFactory(config);
        return connectionFactory;
    }
    
    @Bean
    public RedisTemplate<String, Serializable> redisTemplate(JedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setConnectionFactory(jedisConnectionFactory());
        return redisTemplate;
    }
}

(3)为什么要自定义RredisTemplate?

在引入redis的依赖后,RredisTemplate会自动配置,可以直接注入RedisTemplate使用。看源码:
Spring Boot 自动帮我们在容器中生成了一个RedisTemplate和一个StringRedisTemplate。但是,这个RedisTemplate的泛型是<Object,Object>。这样在写代码就很不方便,要写好多类型转换的代码。

@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
 
    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<Object, Object> redisTemplate(
            RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
 
    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(
            RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
 
}

因为有@ConditionalOnMissingBean(name = “redisTemplate”)注解,
所以如果在Spring容器中,我们自定义一个name 为“redisTemplate” 的 RedisTemplate 对象,这个自动配置的RedisTemplate就不会被实例化
【注意:正如此章节(1)(2)中自定义的redisTemplate方法名一定要叫“redisTemplate ”,因为@Bean注解是根据“方法名”配置这个bean的name的。此时达到覆盖默认配置的目地】

【例】 配置一个RredisTemplate

配置一个泛型为<String,Object>形式的RedisTemplate。
设置这个RedisTemplate把数据存入Redis时key-value的序列化方式
(ps:默认使用的序列化方式是JdkSerializationRedisSerializer,用默认的这样的序列化方式,通过redis desktop manager查看存入的k-v时,显示的key-value不是正常字符)

@Configuration
public class RedisConfig {
  @Bean
  public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
    RedisTemplate<String,Object> template = new RedisTemplate <>();
    template.setConnectionFactory(factory);
 
    StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
     
    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    ObjectMapper om = new ObjectMapper();
    om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    jackson2JsonRedisSerializer.setObjectMapper(om);

    // key采用String的序列化方式
    template.setKeySerializer(stringRedisSerializer);
    // hash的key也采用String的序列化方式
    template.setHashKeySerializer(stringRedisSerializer);
    // value序列化方式采用jackson
    template.setValueSerializer(jackson2JsonRedisSerializer);
    // hash的value序列化方式采用jackson
    template.setHashValueSerializer(jackson2JsonRedisSerializer);
    template.afterPropertiesSet();
 
    return template;
  }
}

Redis 操作的工具类

/**
 * redis 工具类
 **/
 @Component
 public class RedisUtils {
   /**
    * 注入redisTemplate bean
    */
   @Autowired
   private RedisTemplate <String,Object> redisTemplate;
 
   /**
    * 指定缓存失效时间
    *
    * @param key  键
    * @param time 时间(秒)
    * @return
    */
   public boolean expire(String key, long time) {
     try {
       if (time > 0) {
         redisTemplate.expire(key, time, TimeUnit.SECONDS);
       }
       return true;
     } catch (Exception e) {
       e.printStackTrace();
       return false;
     }
   }
 
   /**
    * 根据key获取过期时间
    *
    * @param key 键 不能为null
    * @return 时间(秒) 返回0代表为永久有效
    */
   public long getExpire(String key) {
     return redisTemplate.getExpire(key, TimeUnit.SECONDS);
   }
 
   /**
    * 判断key是否存在
    *
    * @param key 键
    * @return true 存在 false不存在
    */
   public boolean hasKey(String key) {
     try {
       return redisTemplate.hasKey(key);
     } catch (Exception e) {
       e.printStackTrace();
       return false;
     }
   }
 
   /**
    * 删除缓存
    *
    * @param key 可以传一个值 或多个
    */
   @SuppressWarnings("unchecked")
   public void del(String... key) {
     if (key != null && key.length > 0) {
       if (key.length == 1) {
         redisTemplate.delete(key[0]);
       } else {
         redisTemplate.delete(CollectionUtils.arrayToList(key));
       }
     }
   }
   // ============================String(字符串)=============================
 
   /**
    * 普通缓存获取
    *
    * @param key 键
    * @return 值
    */
   public Object get(String key) {
     return key == null ? null : redisTemplate.opsForValue().get(key);
   }
 
   /**
    * 普通缓存放入
    *
    * @param key   键
    * @param value 值
    * @return true成功 false失败
    */
   public boolean set(String key, Object value) {
     try {
       redisTemplate.opsForValue().set(key, value);
       return true;
     } catch (Exception e) {
       e.printStackTrace();
       return false;
     }
   }
 
   /**
    * 普通缓存放入并设置时间
    *
    * @param key   键
    * @param value 值
    * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
    * @return true成功 false 失败
    */
   public boolean set(String key, Object value, long time) {
     try {
       if (time > 0) {
         redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
       } else {
         set(key, value);
       }
       return true;
     } catch (Exception e) {
       e.printStackTrace();
       return false;
     }
   }
 
   /**
    * 递增
    *
    * @param key   键
    * @param delta 要增加几(大于0)
    * @return
    */
   public long incr(String key, long delta) {
     if (delta < 0) {
       throw new RuntimeException("递增因子必须大于0");
     }
     return redisTemplate.opsForValue().increment(key, delta);
   }
 
   /**
    * 递减
    *
    * @param key   键
    * @param delta 要减少几(小于0)
    * @return
    */
   public long decr(String key, long delta) {
     if (delta < 0) {
       throw new RuntimeException("递减因子必须大于0");
     }
     return redisTemplate.opsForValue().increment(key, -delta);
   }
   // ================================Hash(哈希)=================================
 
   /**
    * HashGet
    *
    * @param key  键 不能为null
    * @param item 项 不能为null
    * @return 值
    */
   public Object hget(String key, String item) {
     return redisTemplate.opsForHash().get(key, item);
   }
 
   /**
    * 获取hashKey对应的所有键值
    *
    * @param key 键
    * @return 对应的多个键值
    */
   public Map <Object, Object> hmget(String key) {
     return redisTemplate.opsForHash().entries(key);
   }
 
   /**
    * HashSet
    *
    * @param key 键
    * @param map 对应多个键值
    * @return true 成功 false 失败
    */
   public boolean hmset(String key, Map <String, Object> map) {
     try {
       redisTemplate.opsForHash().putAll(key, map);
       return true;
     } catch (Exception e) {
       e.printStackTrace();
       return false;
     }
   }
 
   /**
    * HashSet 并设置时间
    *
    * @param key  键
    * @param map  对应多个键值
    * @param time 时间(秒)
    * @return true成功 false失败
    */
   public boolean hmset(String key, Map <String, Object> map, long time) {
     try {
       redisTemplate.opsForHash().putAll(key, map);
       if (time > 0) {
         expire(key, time);
       }
       return true;
     } catch (Exception e) {
       e.printStackTrace();
       return false;
     }
   }
 
   /**
    * 向一张hash表中放入数据,如果不存在将创建
    *
    * @param key   键
    * @param item  项
    * @param value 值
    * @return true 成功 false失败
    */
   public boolean hset(String key, String item, Object value) {
     try {
       redisTemplate.opsForHash().put(key, item, value);
       return true;
     } catch (Exception e) {
       e.printStackTrace();
       return false;
     }
   }
 
   /**
    * 向一张hash表中放入数据,如果不存在将创建
    *
    * @param key   键
    * @param item  项
    * @param value 值
    * @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
    * @return true 成功 false失败
    */
   public boolean hset(String key, String item, Object value, long time) {
     try {
       redisTemplate.opsForHash().put(key, item, value);
       if (time > 0) {
         expire(key, time);
       }
       return true;
     } catch (Exception e) {
       e.printStackTrace();
       return false;
     }
   }
 
   /**
    * 删除hash表中的值
    *
    * @param key  键 不能为null
    * @param item 项 可以使多个 不能为null
    */
   public void hdel(String key, Object... item) {
     redisTemplate.opsForHash().delete(key, item);
   }
 
   /**
    * 判断hash表中是否有该项的值
    *
    * @param key  键 不能为null
    * @param item 项 不能为null
    * @return true 存在 false不存在
    */
   public boolean hHasKey(String key, String item) {
     return redisTemplate.opsForHash().hasKey(key, item);
   }
 
   /**
    * hash递增 如果不存在,就会创建一个 并把新增后的值返回
    *
    * @param key  键
    * @param item 项
    * @param by   要增加几(大于0)
    * @return
    */
   public double hincr(String key, String item, double by) {
     return redisTemplate.opsForHash().increment(key, item, by);
   }
 
   /**
    * hash递减
    *
    * @param key  键
    * @param item 项
    * @param by   要减少记(小于0)
    * @return
    */
   public double hdecr(String key, String item, double by) {
     return redisTemplate.opsForHash().increment(key, item, -by);
   }
   // ============================Set(集合)=============================
 
   /**
    * 根据key获取Set中的所有值
    *
    * @param key 键
    * @return
    */
   public Set <Object> sGet(String key) {
     try {
       return redisTemplate.opsForSet().members(key);
     } catch (Exception e) {
       e.printStackTrace();
       return null;
     }
   }
 
   /**
    * 根据value从一个set中查询,是否存在
    *
    * @param key   键
    * @param value 值
    * @return true 存在 false不存在
    */
   public boolean sHasKey(String key, Object value) {
     try {
       return redisTemplate.opsForSet().isMember(key, value);
     } catch (Exception e) {
       e.printStackTrace();
       return false;
     }
   }
 
   /**
    * 将数据放入set缓存
    *
    * @param key    键
    * @param values 值 可以是多个
    * @return 成功个数
    */
   public long sSet(String key, Object... values) {
     try {
       return redisTemplate.opsForSet().add(key, values);
     } catch (Exception e) {
       e.printStackTrace();
       return 0;
     }
   }
 
   /**
    * 将set数据放入缓存
    *
    * @param key    键
    * @param time   时间(秒)
    * @param values 值 可以是多个
    * @return 成功个数
    */
   public long sSetAndTime(String key, long time, Object... values) {
     try {
       Long count = redisTemplate.opsForSet().add(key, values);
       if (time > 0)
         expire(key, time);
       return count;
     } catch (Exception e) {
       e.printStackTrace();
       return 0;
     }
   }
 
   /**
    * 获取set缓存的长度
    *
    * @param key 键
    * @return
    */
   public long sGetSetSize(String key) {
     try {
       return redisTemplate.opsForSet().size(key);
     } catch (Exception e) {
       e.printStackTrace();
       return 0;
     }
   }
 
   /**
    * 移除值为value的
    *
    * @param key    键
    * @param values 值 可以是多个
    * @return 移除的个数
    */
   public long setRemove(String key, Object... values) {
     try {
       Long count = redisTemplate.opsForSet().remove(key, values);
       return count;
     } catch (Exception e) {
       e.printStackTrace();
       return 0;
     }
   }
   // ===============================List(列表)=================================
 
   /**
    * 获取list缓存的内容
    *
    * @param key   键
    * @param start 开始
    * @param end   结束 0 到 -1代表所有值
    * @return
    */
   public List <Object> lGet(String key, long start, long end) {
     try {
       return redisTemplate.opsForList().range(key, start, end);
     } catch (Exception e) {
       e.printStackTrace();
       return null;
     }
   }
 
   /**
    * 获取list缓存的长度
    *
    * @param key 键
    * @return
    */
   public long lGetListSize(String key) {
     try {
       return redisTemplate.opsForList().size(key);
     } catch (Exception e) {
       e.printStackTrace();
       return 0;
     }
   }
 
   /**
    * 通过索引 获取list中的值
    *
    * @param key   键
    * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
    * @return
    */
   public Object lGetIndex(String key, long index) {
     try {
       return redisTemplate.opsForList().index(key, index);
     } catch (Exception e) {
       e.printStackTrace();
       return null;
     }
   }
 
   /**
    * 将list放入缓存
    *
    * @param key   键
    * @param value 值
    * @return
    */
   public boolean lSet(String key, Object value) {
     try {
       redisTemplate.opsForList().rightPush(key, value);
       return true;
     } catch (Exception e) {
       e.printStackTrace();
       return false;
     }
   }
 
   /**
    * 将list放入缓存
    *
    * @param key   键
    * @param value 值
    * @param time  时间(秒)
    * @return
    */
   public boolean lSet(String key, Object value, long time) {
     try {
       redisTemplate.opsForList().rightPush(key, value);
       if (time > 0)
         expire(key, time);
       return true;
     } catch (Exception e) {
       e.printStackTrace();
       return false;
     }
   }
 
   /**
    * 将list放入缓存
    *
    * @param key   键
    * @param value 值
    * @return
    */
   public boolean lSet(String key, List <Object> value) {
     try {
       redisTemplate.opsForList().rightPushAll(key, value);
       return true;
     } catch (Exception e) {
       e.printStackTrace();
       return false;
     }
   }
 
   /**
    * 将list放入缓存
    *
    * @param key   键
    * @param value 值
    * @param time  时间(秒)
    * @return
    */
   public boolean lSet(String key, List <Object> value, long time) {
     try {
       redisTemplate.opsForList().rightPushAll(key, value);
       if (time > 0)
         expire(key, time);
       return true;
     } catch (Exception e) {
       e.printStackTrace();
       return false;
     }
   }
 
   /**
    * 根据索引修改list中的某条数据
    *
    * @param key   键
    * @param index 索引
    * @param value 值
    * @return
    */
   public boolean lUpdateIndex(String key, long index, Object value) {
     try {
       redisTemplate.opsForList().set(key, index, value);
       return true;
     } catch (Exception e) {
       e.printStackTrace();
       return false;
     }
   }
 
   /**
    * 移除N个值为value
    *
    * @param key   键
    * @param count 移除多少个
    * @param value 值
    * @return 移除的个数
    */
   public long lRemove(String key, long count, Object value) {
     try {
       Long remove = redisTemplate.opsForList().remove(key, count, value);
       return remove;
     } catch (Exception e) {
       e.printStackTrace();
       return 0;
     }
   }
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值