内存数据库Redis使用指南

Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。它也被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。

安装Redis(Mac环境)

前往Redis的官网的下载页面,选择Stable版本下载
https://redis.io/download
接下来打开终端(此处展示的5.0.5版本的Redis)

# 解压安装包
tar xzf redis-5.0.5.tar.gz
# 将解压后的文件夹移动到“/usr/local/”下
mv redis-5.0.5 /usr/local/
# 进入软件对应路径
cd /usr/local/redis-5.0.5
# 测试编译
sudo make test
# 正式编译
sudo make install

安装完成之后一般会在终端看到Redis的图标和一些基础信息说明。

image.png

接下来我们可以将Redis的配置文件复制到/usr/local/etc/方便启动

cp /usr/local/redis-5.0.5/redis.conf /usr/local/etc

安装Redis(Ubuntu18.04环境)

在Ubuntu环境下安装Redis比较简单

sudo apt-get update
sudo apt-get install redis-server
# 完成上述两步之后便可将Redis安装在本机上
# 接着我们可以通过执行“redis-cli”来测试是否成功安装上了Redis
redis-cli # 进入Redis的终端中
ping # 若返回一个“pong”字符,则表示安装成功

# 安装成功后Redis的配置文件存放位置为“/etc/redis/redis.conf”
# 将配置文件中的三个位置做更改
bind 192.168.xxx.xxx # 这里写微服务的服务器,若是直接注释掉则代表任何IP都能访问
protected-mode no # 将保护模式关闭
daemonize yes # 开启后台运行

Redis相关指令

  • 直接启动Redis:redis-server
  • 携带配置文件启动Redis(根据上方的配置路径):redis-server /usr/local/etc/redis.conf
  • 启动Redis-cli客户端:redis-cli
  • 查看Redis日志:tail -f log-redis.log
  • 前台关闭Redis:Ctrl + C
  • 通过Redis-cli来关闭Redis:SHUTDOWN 强制关闭为SHUTDOWN NOSAVE

redis.conf配置文件相关功能说明

redis.conf是对redis数据库的基础使用配置,方便我们更好的控制Redis相关功能。

#修改为守护模式,若想让Redis后台启动需要此处为yes
daemonize yes

#设置进程锁文件
pidfile /usr/local/redis/redis.pid

#端口
port 6379

#客户端超时时间,单位为秒
timeout 300

#日志级别
loglevel debug

#日志文件位置
logfile /usr/local/redis/log-redis.log

#设置数据库的数量,默认数据库为0,可以使用SELECT <dbid>命令在连接上指定数据库id
databases 8

#指定在多长时间内,有多少次更新操作,就将数据同步到数据文件 (save <秒数> <更新次数>)
#Redis默认持久化方案(rdb)配置提供了三个条件:
save 900 1
save 300 10
save 60 10000

#指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩,如果为了节省CPU时间,可以关闭该#选项,但会导致数据库文件变的巨大
rdbcompression yes

#指定本地数据库文件名
dbfilename dump.rdb

#指定本地数据库路径
dir /usr/local/redis/db/

#指定是否让Redis执行AOF持久化方案,默认为no则代表使用默认rdb持久化方案,具体配置根据上方的三个save为准
appendonly no

#指定AOF更新日志的方式,需要在上方的appendonly属性为yes时使用,共有3个可选值:
#no:表示等操作系统进行数据缓存同步到磁盘(快)
#always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)
#everysec:表示每秒同步一次(折衷,默认值)
appendfsync everysec

Redis五大数据类型及各数据类型的常用方法

Redis中的数据不依附于数据表,都是以独立的键值对的形式存在,其中值的数据类型可以大致分为五大类,他们分别是:StringHashListSetZset

通用方法如下
  • 查看所有已创建的键:keys *
  • 获取某键值的数据类型:type 键名
  • 删除键值对:del 键名
String类型的数据值类似于Java中的Map<String,String>,常见方法如下
  • 设置键值对:set 键名 值
  • 获取值:get 键名
  • 数据值加一(值为数字):incr 键名
  • 数据值加一(值为数字):decr 键名
  • 数据值加n(值为数字):incrby 键名 n
  • 数据值加n(值为数字):decrby 键名 n
Hash类型的数据值类似于Java中的Map<String,Map<String,String>>,子键值需要根据需求添加引号,常见方法如下
  • 设置某主健的单个子键的值:hset 主键名 子键名 子健值
  • 设置某主健的多个子键值对:hmset 主键名 子键名1 子键值1 子键名2 子键值2 ...
  • 获取某个子健的值:hget 主键名 子键名
  • 获取某主健的所有子键值对:hgetall 主键名
List类型的数据值类似于Java中的Map<String,List<String>>,类似于一段管道,可以左右插值,常见方法如下
  • 从左边依次插入若干个值:lpush 键名 值1 值2 值3 ... 注意此时管道中的数据为:“值3,值2,值1”
  • 从右边依次插入若干个值:rpush 键名 值1 值2 值3 ...
  • 从左到右获取若干个值:lrange 键名 开始序号 结束序号 序号从0开始计算,最后一位可用-1表示
  • 删除当前最左边的值:lpop 键名
  • 删除当前最右边的值:rpop 键名
Set类型的数据值是无序且唯一的,类似于Java中的Map<String,Set<String>>,常见方法如下
  • 设置键值对:sadd 键名 值1 值2 值3 ...
  • 获取某个键的值:smembers 键名
  • 获取两个键值的交集:sinter 键名1 键名2
  • 获取两个键值的并集:sunion 键名1 键名2
  • 删除键中的某个值:srem 键名 值
Zset类型(SortedSet)的数据值跟Set是类似的,但Zset是有序的,常见方法如下
  • 设置键值对:zadd 键名 序号1 值1 序号2 值2 ...若添加了重复的值,会更新该值的序号
  • 升序获取键的值:zrange 键名 开始序号 结束序号 [withscores] 序号从0开始计算,最后一位可用-1表示(该序号不是自定义的序号值,而是数据在键中的位置);withscores可选,加上代表显示数据时带上自定义序号
  • 降序获取键的值:zrevrange 键名 开始序号 结束序号 [withscores]
  • 获取键中某个值的自定义序号:zscore 键名 值
  • 删除键中的某个值:zrem 键名 值

使用Jedis快速操作Redis

在配置好redis.conf文件之后,我们携带该配置文件启动Redis;随后打开我们的项目,并在项目添加如下依赖。Jedis是Java连接Redis数据库的一个工具,能够让我们在日常开发中比较方便的操作Redis数据库。

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

依赖添加完成后,我们便可以尝试简单的操作以下Redis数据库

public void test() {
    //创建Jedis对象
    Jedis jedis = new Jedis("127.0.0.1",6379);
    //创建普通键值对
    jedis.set("demo_key1","demo_value1");
    //创建有效时长键值对,中间参数为有效时间,单位为秒,此处代表该数据只会存活20秒钟,过期自动删除
    jedis.setex("demo_key2",20,"demo_value2");
    //获取键的值
    System.out.println("当前键的值为:" + jedis.get("demo_key1"));
    //释放资源
    jedis.close();
}

操作其余四种数据类型的方法与原命令基本大同小异,就不一一展示了。


使用RedisTemplate整合SpringBoot操作Redis

RedisTemplate是Spring官方推荐使用的整合SpringBoot操作Redis的工具类。
Lettuce 是一个可伸缩的线程安全的 Redis 客户端,支持同步、异步和响应式模式。他比传统的Jedis在多个线程上更有优势,它能够在多个线程上共享一个连接实例,从而不必担心多线程并发问题。

要想使用RedisTemplate,必不可少的添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>2.1.7.RELEASE</version>
</dependency>
<!-- 下方依赖是Redis的连接池依赖 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.4.2</version>
</dependency>

接着在项目中的配置文件application.yml中添加关于Redis的相关配置

spring:
  redis:
    database: 0 # Redis默认情况下有16个分片,这里配置具体使用的分片,默认是0
    host: 127.0.0.1
    port: 6379
    password:  # 有密码就写
    cluster:
      nodes: # 集群相关节点
      - 127.0.0.1:6860
      - 127.0.0.1:6861
      - 127.0.0.1:6862
    lettuce:
      pool:
        # 连接池中的最大空闲连接 默认8      
        max-idle: 8
        # 连接池中的最小空闲连接 默认0
        min-idle: 0
        # 连接池最大连接数 默认8 ,负数表示没有限制
        max-active: 8
        # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认-1
        max-wait: -1
    # 配置超时时长,单位为毫秒
    timeout: 30000

在写好配置之后,由于RedisTemplate默认只支持RedisTemplate<String, String>类型的数据,相对有局限性,所以此时我们需要编写一个配置类。之后String类型的数据也可以通过SpringRedisTemplate来操作,其余类型的数据通过RedisTemplate来操作。

@Configuration
public class RedisConfiguration {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory){
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }
}

接下来我们要了解RedisTemplate在操作Redis五大数据类型时的形态,后续的操作方法在此形态下分类操作
前提准备: private RedisTemplate redisTemplate;

针对不同数据类型的操作分类:
操作String:redisTemplate.opsForValue()
操作Hash:redisTemplate.opsForHash()
操作List:redisTemplate.opsForList()
操作Set:redisTemplate.opsForSet()
操作Zset:redisTemplate.opsForZSet()

知道了RedisTemplate不同分类的方法前缀之后,此时我们就可以进一步了解一些详细的操作方法

操作String:redisTemplate.opsForValue()
//设置单个键值对
redisTemplate.opsForValue().set("demo_key","demo_value");
//设置单个键值对,在创建时会检查当前键是否存在,若存在不会修改这个键值对
redisTemplate.opsForValue().setIfAbsent("demo_key","demo_value");
//在原有值之上覆写值,会在num下标位置开始覆写
//例如:["demo_key":"hello world"]执行set("demo_key","redis",6)之后变为["demo_key":"hello redis"]
Long new_num = redisTemplate.opsForValue().set("demo_key","demo_value",long_num);
//设置有生命周期的键值对,此时生命周期的单位为秒,最后一个参数固定
redisTemplate.opsForValue().set("demo_key","demo_value",long_num,TimeUnit.SECONDS);
//获取值
String my_value = redisTemplate.opsForValue().get("demo_key");
//获取值的一部分,即对值做截取,序号从0开始,默认最后一位为-1
String my_value = redisTemplate.opsForValue().get("demo_key",start_num,end_num);
//设置多个键值对,其中参数是一个Map<K,V>对象
redisTemplate.opsForValue(). multiSet(Map<K,V>);
//获取多个值,其中参数是一个Map<K,V>对象
List<String> value_list = redisTemplate.opsForValue(). multiGet(List<String>);
//获取值的同时将原有值进行替换,返回原有值
String old_value = redisTemplate.opsForValue(). getAndSet("demo_key","demo_value_new");
//在原有值之上追加值
redisTemplate.opsForValue().append("demo_key","demo_value_append");
//获取指定键值的字符串长度
Long value_length = redisTemplate.opsForValue().size("demo_key");
//对指定的键值进行增量运算,第二个参数代表增量的数值
redisTemplate.opsForValue().increment("demo_key",long_num);
操作Hash:redisTemplate.opsForHash()
//为键内部添加单个键值对
redisTemplate.opsForHash().put("demo_key","child_key","child_value");
//为键内部添加单个键值对,在添加之间会判断当前键中是否已经有这个子键了,没有才会执行添加
redisTemplate.opsForHash(). putIfAbsent("demo_key","child_key","child_value");
//为键内部添加多个键值对
redisTemplate.opsForHash().putAll("demo_key",Map<String,Object>);
//判断键中是否含有指定子键
redisTemplate.opsForHash().hasKey("demo_key","child_key");
//获取键中指定子键的值
V my_value = redisTemplate.opsForHash().get("demo_key","child_key");
//获取键中子键的个数(长度)
Long length = redisTemplate.opsForHash().size("demo_key");
//获取键中所有的子键名
List<String> list_key = redisTemplate.opsForHash().keys("demo_key");
//获取键中所有的值
List<V> list_value = redisTemplate.opsForHash().values("demo_key");
//获取键中多个子键的值
List<V> value_list = redisTemplate.opsForHash().multiGet("demo_key",List<String>);
//获取键中所有的键值对
Map<string,V> my_list = redisTemplate.opsForHash().entries("demo_key");
//对键中指定子键的值进行增量运算,第三个参数代表child_key对应值的增减量,返回值为计算后的值
Long new_num = redisTemplate.opsForHash().increment("demo_key","child_key",long_num);
//删除键中指定的子键值对
redisTemplate.opsForHash().delete("demo_key","child_key");
操作List:redisTemplate.opsForList()

下列方法中只写了关于左边操作的方法,右边操作的方法将对应的方法名中的left更换为right即可

//从列表最左边添加单个值
redisTemplate.opsForList().leftPush("demo_key","demo_value");
//从列表最左边添加单个值,不过在添加时会先查看当前键中是否已经存在相同的值了,存在才会添加
redisTemplate.opsForList(). leftPushIfPresent("demo_key","demo_value");
//从特定值左边添加单个值,即等于在old_value值的左边添加demo_value这个值
redisTemplate.opsForList().leftPush("demo_key","another_value","demo_value");
//从列表最左边添加多个值,第二个参数可以是一个字符串数组,也可以时一个集合类型对象
redisTemplate.opsForList().leftPushAll("demo_key",String[]/Collection<V>);
//获取获取值的一部分,即对取值做截取,不改变原键值对,序号从0开始,默认最后一位为-1
List<V> value_list = redisTemplate.opsForList().range("demo_key",start_num,end_num);
//裁切指定的键值对,与上条语句不同的是这个是在原始数据上直接动刀,序号从0开始,默认最后一位为-1
redisTemplate.opsForList().trim("demo_key",start_num,end_num);
//获取当前键值的列表长度,若该键值对不是List类型会报错
Long value_length = redisTemplate.opsForList().size("demo_key");
//根据下标值获取某键的值,下标从0开始计算
V my_value = redisTemplate.opsForList().index("demo_key",long_num);
//替换某键指定下标位置的值,从0开始计算
redisTemplate.opsForList().set("demo_key",long_num,"demo_value");
//删除某键指定的值,第二个参数代表出现的顺序
//如果long_count为正数代表从左到右计算,为负则代表从右到左计算,为0代表所有值等于demo_value的值
redisTemplate.opsForList().remove("demo_key",long_count,"demo_value");
//删除列表最左边的第一个值
redisTemplate.opsForList().leftPop("demo_key");
//定时删除列表最左边的第一个值
redisTemplate.opsForList().leftPop("demo_key",long_num,TimeUnit.SECONDS);
//删除键1最右边的值,同时将这个删除的值从左边添加到键2
//例如:原来有["demo_key1":{"a","b","c"}]["demo_key2":{"d","e"}]
//     该操作执行完之后变为["demo_key1":{"a","b"}]["demo_key2":{"c","d","e"}]
redisTemplate.opsForList().rightPopAndLeftPush("demo_key1","demo_key2");
//定时删除键1最右边的值,同时将这个删除的值从左边添加到键2
redisTemplate.opsForList().rightPopAndLeftPush("demo_key1","demo_key2",long_num,TimeUnit.SECONDS);
操作Set:redisTemplate.opsForSet()

下列方法中只写了关于左边操作的方法,右边操作的方法将对应的方法名中的left更换为right即可

//为键添加若干个值
redisTemplate.opsForSet().add("demo_key","demo_value"/V[]);
//删除键中的若干个值
redisTemplate.opsForSet().remove("demo_key","demo_value"/V[]);
//删除键中随机的一个值,并返回这个值
redisTemplate.opsForSet().pop("demo_key");
//将一个键中的指定值转移到另一个键上
redisTemplate.opsForSet().move("demo_key1","demo_value","demo_key2");
//获取键中值的数量
Long value_length = redisTemplate.opsForSet().size("demo_key");
//判断指定值是否存在于键中
redisTemplate.opsForSet().isMember("demo_key","demo_value");
//获取当前键中所有的值
Set<V> my_values = redisTemplate.opsForSet().members("demo_key","demo_value");
//获取当前键中的随机一个值
V my_value = redisTemplate.opsForSet().randomMember("demo_key","demo_value");
//对当前键及若干个键之间取交集
Set<V> value_set = redisTemplate.opsForSet().intersect("demo_key1","demo_key2"/List<String>);
//对当前键及若干个键之间取交集,并将这个交集存入一个新的键中
redisTemplate.opsForSet().intersectAndStore("demo_key1","demo_key2"/List<String>,"demo_key3");
//对当前键及若干个键之间取并集
Set<V> value_set = redisTemplate.opsForSet().union("demo_key1","demo_key2"/List<String>);
//对当前键及若干个键之间取并集,并将这个并集存入一个新的键中
redisTemplate.opsForSet().unionAndStore("demo_key1","demo_key2"/List<String>,"demo_key3");
//对当前键及若干个键之间取差集
Set<V> value_set = redisTemplate.opsForSet().difference("demo_key1","demo_key2"/List<String>);
//对当前键及若干个键之间取差集,并将这个差集存入一个新的键中
redisTemplate.opsForSet().differenceAndStore("demo_key1","demo_key2"/List<String>,"demo_key3");
//获取当前键中的随机多个值
Set<V> value_set = redisTemplate.opsForSet(). distinctRandomMembers("demo_key",long_num);
//获取当前键中的随机多个值,可以重复获取
List<V> value_list = redisTemplate.opsForSet().randomMembers("demo_key",long_num);
//获取当前键的游标,可以对该键执行遍历 (通过“curosr.hasNext()”和“curosr.next()”)
Cursor<Object> curosr = redisTemplate.opsForSet(). scan("demo_key",ScanOptions.NONE);
操作ZSet:redisTemplate.opsForZSet()

下列方法中只写了关于左边操作的方法,右边操作的方法将对应的方法名中的left更换为right即可

//为键添加一个值,第三个参数是序号
redisTemplate.opsForZSet().add("demo_key","demo_value",double_num);
//为键的原始值做增量计算,第三个参数是增量值
redisTemplate.opsForZSet().incrementScore("demo_key","demo_value",double_num);
//为键添加多个值
ZSetOperations.TypedTuple<Object> new_zset1 = new DefaultTypedTuple<Object>("demo_value1",double_num1);
ZSetOperations.TypedTuple<Object> new_zset2 = new DefaultTypedTuple<Object>("demo_value2",double_num2);
Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<ZSetOperations.TypedTuple<Object>>();
tuples.add(new_zset1);
tuples.add(new_zset2);
redisTemplate.opsForZSet().add("demo_key",tuples);
//获取键中的所有值(升序排序),序号从0开始,默认最后一位为-1
Set<V> values = redisTemplate.opsForZSet().range("demo_key",start_num,end_num);
//获取键中的所有值(降序排序),序号从0开始,默认最后一位为-1
Set<V> values = redisTemplate.opsForZSet().reverseRange("demo_key",start_num,end_num);
//获取键中的所有值(升序排序),此处序号为自定义序号值
Set<V> values = redisTemplate.opsForZSet().rangeByScore("demo_key",start_num,end_num);
//获取键中的所有值(降序排序),此处序号为自定义序号值
Set<V> values = redisTemplate.opsForZSet(). reverseRangeByScore("demo_key",start_num,end_num);
//获取键中指定值的自定义序号
Double value_num = redisTemplate.opsForZSet().score("demo_key","demo_value");
//获取键中值的数量
Long value_num = redisTemplate.opsForZSet().size("demo_key");
//获取键中值一定范围的数量,其中范围为自定义序号的范围,不是值在ZSet中的顺序下标
Long value_num = redisTemplate.opsForZSet().count("demo_key",start_num,end_num);
//获取指定值在键中的升序排序下标
Long value_index = redisTemplate.opsForZSet().rank("demo_key","demo_value");
//获取指定值在键中的降序排序下标
Long value_index = redisTemplate.opsForZSet().reverseRank("demo_key","demo_value");
//删除键中指定下标范围的值
redisTemplate.opsForZSet().removeRange("demo_key",start_num,end_num);
//删除键中指定自定义序号范围的值
redisTemplate.opsForZSet().removeRangeByScore("demo_key",start_num,end_num);
//对当前键及若干个键之间取交集,并将这个交集存入一个新的键中
redisTemplate.opsForZSet().intersectAndStore("demo_key1","demo_key2"/List<String>,"demo_key3");
//对当前键及若干个键之间取并集,并将这个并集存入一个新的键中
redisTemplate.opsForZSet().unionAndStore("demo_key1","demo_key2"/List<String>,"demo_key3");
//获取当前键的游标,可以对该键执行遍历 (通过“curosr.hasNext()”和“curosr.next()”)
//其中每一个next得到的是ZSetOperations.TypedTuple<Object>对象,还需要结合“getValue()”和“getScore()”
Cursor<Object> curosr = redisTemplate.opsForZSet(). scan("demo_key",ScanOptions.NONE);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容