Redis由入门到精通

引言

Redis是一种基于键值对(key-value)的高性能的NoSql数据库,它提供了各种数据结构存储,具有高性能的读写功能,是目前企业中应用极其广泛的一种数据库。

官网:https://redis.io

1. NoSql数据库简介

1.1 技术发展

web1.0时代,数据访问量很有限,用高性能的单点服务器可以解决大部分问题。随着web2.0时代的到来后,用户访问量大幅度的提升,同时产生了大量的用户数据,加上后来的智能移动设备的普及,所有的互联网平台都面临了巨大的性能挑战,其实主要的挑战来自于服务器的CPU及内存压力以及MySql的读写IO压力 。

1.2 NoSql数据库
1.2.1 NoSql的概念

NoSql不要理解成“不是SQL”,是指“Not Only Sql”,意为不仅仅是Sql,它里面既有SQL,还有SQL不能解决的问题,泛指非关系型数据库。NoSql不依赖业务逻辑的方式存储,而以简单的Key-Value模式存储,因此大大的增加了数据库的扩展能力。

  • 不遵守SQL标准

  • 不支持ACID

  • 远超于SQL的性能

1.2.2 适用场景
  • 对数据高并发的读写

  • 海量数据的读写 Nosql吞吐量

1.2.3 常见的NoSql数据库
  • Memcache

    • 是一款很早就出现的数据库

    • 数据都在内存中,一般 不支持持久化

    • 支持简单的key-value模式,支持类型单一。

    • 一般是作为缓存数据库辅助持久化的数据库。

  • Redis

    • 几乎覆盖了Memcache的绝大部分功能

    • 数据都在内存中,支持持久化,主要用作备份恢复。

    • 除了支持简单的key-value模式,还支持多种数据结构的存储,比如list、set、hash、zset等

    • 也是作为缓存数据库辅助持久化的数据库。

  • MongoDB

    • 高性能,开源、模式自由的文档型数据库

    • 数据都在内存中,如果内存不足,把不常用的数据保存在硬盘中

    • 虽然是key-value模式,但是对value,尤其是json提供了丰富的查询功能

    • 支持二进制及大型对象

2. Redis概述和安装

2.1 Redis概述

Redis 是完全开源免费的,是一个高性能的key-value数据库。Redis的性能十分优越,可以支持每秒十几万的读/写操作,其性能远超关系型数据库,并且支持集群、分布式、主从同步等配置,还支持一定事务的能力。

2.2 Redis在JavaWeb中的应用

在互联网的应用中,往往存在一些需要高速读/写的场合,比如商品的秒杀,抢红包,淘宝、京东的双十一活动或者春运抢票等。这类场合在一个瞬间成千上万的请求就会达到服务器,如果使用的是关系型数据库, 一个瞬间数据库就需要执行成千上万的SQL ,很容易造成数据库的瓶颈,严重的会导致数据库瘫痪,造成Java Web 系统服务崩溃。

在这样的场合的应对办法往往是考虑异步写入数据库,而在高速读/写的场合中单单使用Redis 去应对, 把这些需要高速读/写的数据, 缓存到Redis 中,而在满足一定的条件下,触发这些缓存的数据写入数据库中。

咱们再进一步深入论述这个过程: 当一个请求达到服务器,只是把业务数据先在Redis 读/写,而没有进行任何对数据库的操作,换句话说系统仅仅是操作Redis 缓存,而没有操作数据库,这个速度就比操作数据库要快得多,从而达到需要高速响应的效果。

但是一般缓存不能持久化,因此需要把这些数据存入数据库,所以在一个请求操作完Redis 的读/写后,会去判断该高速读/写的业务是否结束。这个判断的条件往往就是秒杀商品剩余个数为0 ,抢红包金额为0 ,如果不成立,则不会操作数据库;如果成立,则触发事件将Redis 缓存的数据以批量的形式一次性写入数据库,从而完成持久化的工作。

假设面对的是一个商品秒杀的场景,从上面的流程看, 一个用户抢购商品,绝大部分的场合都是在操作内存数据库Redis , 而不是磁盘mysql数据库,所以其性能更为优越。只有在商品被抢购一空后才会触发系统把Redis 缓存的数据写入数据库磁盘中, 这样系统大部分的操作基于内存,就能够在秒杀的场合高速响应用户的请求,达到快速应答。

2.3 Redis的安装
2.3.1 Windows安装步骤

1.下载安装包

**下载地址:**https://github.com/dmajkic/redis

2.打开你刚才解压的文件路径

3.双击redis-server.exe启动服务

4.使用redis-cli.exe客户端来连接

5.测试连接

输入ping命令,输出PONG代表连接成功

2.3.2 Linux安装步骤

卸载步骤:

查看是否已经安装redis,版本

redis-server -v | redis-cli -v

如果存在

ps - ef | grep redis

关闭服务或者kill进程

kill -9 01234

删除安装目录下的文件

rm -rf /usr/local/bin/redis*

1.在线安装gcc环境

yum install gcc-c++

安装完毕后,查看版本号

gcc -v

2.下载安装包

官网:https://redis.io/

打开中文官网下载:http://www.redis.cn/

3.上传到linux服务器/opt文件下

4.解压压缩包

tar -zxvf  redis-6.2.5.tar.gz

5.进入redis-6.2.5

cd redis-6.2.5

6.执行make命令

make

如果出现:致命错误:jemalloc/jemalloc.h:没有那个文件或目录,则执行下面命令,进行残存文件的清理

make distclean

后,继续执行 make命令,执行完毕后,可再make一次,然后就执行很快了

7.执行命令

make install

redis的默认安装路径和java是一样的,也在/usr下面

8.进入usr目录,找到local下面的bin目录,就可以看到redis-server,自此redis安装就完成了

cd /usr/local/bin
2.3.3 Linux下配置Redis

1.在安装的bin目录下创建文件夹

mkdir redisconfig

2.拷贝文件

cp /opt/redis-6.2.5/redis.conf redisconfig

以后使用这个redisconfig下面的redis.conf就好了,原来的解压目录下的配置文件不需要管了

3.进行后台启动

因为redis不是默认后台启动的,所以得修改配置文件

vim redis.conf

找到daemonize no,把no修改为yes,保存并退出,这样redis就会以后台方式启动

4.启动redis服务

回到 /usr/local/bin目录,运行

cd /usr/local/bin
redis-server redisconfig/redis.conf

意思是通过指定的配置文件redisconfig/redis.conf来启动

5.使用客户端进行连接

redis-cli -p 6379

输入命令

ping

显示PONG,就表示连接成功!

6.测试连接

keys *
set name mengshujun
get name

可以查看里面还有哪些键

7.查看redis的进程是否开启

在xshell中,复制一个会话,输入

ps -ef | grep redis

8.关闭redis服务

在127.0.0.1:6379> 下输入

shutdown
exit

3. Redis配置文件

3.1 远程连接配置

bind 127.0.0.1 -:: 1 表示只能接受本机的访问,要通过其他电脑远程进行连接就应该注释,找到后注释掉,默认没有注释。

protected-mode yes 表示开启保护模式,只能通过本机访问,远程不能访问,改为no就可以进行远程访问了

3.2 配置连接密码

修改redis.conf配置文件 

# requirepass foobared
requirepass 866qa@WSDE#

保存后重启redis就可以了

小技巧:

我们通常在vim下要查找字符串的时候, 都是输入 / 或者 ? 加 需要查找的字符串来进行搜索,比如想搜索 requirepass这个单词, 可以输入 /requirepass或者 ?requirepass, 两者的区别是前者是从上往下搜索,后者是从下往上搜索。按n往下搜索。

3.3 关闭linux防火墙

查看linux的防火墙是否关闭

#查看防火墙的启动状态
systemctl status firewalld
# 关闭防火墙
systemctl stop firewalld
#开启防火墙
systemctl start firewalld
#查看开放的端口号
firewall-cmd --list-all
#在防火墙中设置开放的端口号
firewall-cmd --zone=public --add-port=6379/tcp --permanent
#开启端口后,需要重启防火墙才生效
systemctl restart firewalld | firewall-cmd --reload 
# 如果有不用的端口,则进行移除
firewall-cmd --permanent --remove-port=8001/tcp
3.4 连接redis服务

1.xshell连接

redis-cli -h host -p port -a password
#host:远程redis服务器host
#port:远程redis服务端口
#password:远程redis服务密码(无密码的的话就不需要-a参数了)

示例:

redis-cli -h 127.0.0.1 -p 6379 -a 123456

或者,如果有密码,连接的时候也可输入,回车即可。

auth 123456

2.redisdesktop工具连接

4. 常用五大数据类型

基础命令学习

针对key的操作:

redis默认有16个数据库,可以打开相关配置文件进行查看,默认使用的是第0个数据库。

select 【num】 切换数据库,num代表0-15的数字

dbsize 可以查看数据库的大小,里面包含的key的个数

flushdb 清空当前库

flushall 清空(通杀)所有的库

exists key 判断某个Key是否存在

del key删除指定的key数据

unlink key 根据value选择非阻塞删除,仅将key从keyspace元数据中删除,真正的删除会在后续慢慢异步操作

type key 查看key对应的value是什么类型

expire key 10 为给定的key设置过期时间10秒钟

ttl key 查看还有多少秒过期 -1表示永不过期 -2表示已经过期

4.1 Redis字符串(String)

String是Redis最基本的类型, 一个key对应一个value,一个value的最多是512MB。String类型是二进制的安全的,意味着Redis的String可以包含任何数据。比如jpg图片或者序列化对象。

序号命令及描述
1SET key value 设置指定 key 的值
2GET key 获取指定 key 的值。
3GETRANGE key start end 返回 key 中字符串值的子字符
4GETSET key value 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。
5SETNX key value 只有在 key 不存在时设置 key 的值。 分布式锁
6STRLEN key 返回 key 所储存的字符串值的长度。
7MSET key value [key value ...] 同时设置一个或多个 key-value 对。
8MGET key1 [key2..] 获取所有(一个或多个)给定 key 的值。
9MSETNX key value [key value ...] 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。
10INCR key 将 key 中储存的数字值增一。
11DECR key将 key 中储存的数字值减一。
12INCRBY key increment 将 key 所储存的值加上给定的增量值(increment) 。
13DECRBY key decrementkey 所储存的值减去给定的减量值(decrement) 。
14APPEND key value 如果 key 已经存在并且是一个字符串, APPEND 命令将指定的 value 追加到该 key 原来值(value)的末尾。

4.2 Redis列表(List)

特征:有序的,不唯一的

Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边),它的底层实际是一个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能可能会较差。

一个列表最多可以包含4294967295个元素, 超过40亿个元素。

序号命令及描述
1LPUSH key value1 value2 在列表左边添加将一个或多个值
2RPUSH key value1 value2 在列表右边添加添加一个或多个值
3LRANGE key 0 -1 获取列表指定范围内的元素 【-1代表右边第一个 0 -1代表获取所有】
4LPOP key 移出并获取列表的左边的第一个元素 【值在键在,值亡键亡】
5RPOP key 移出列表的最后一个元素,返回值为移出的元素。【值在键在,值亡键亡】
6RPOPLPUSH key1 key2 从key1列表右边移出一个值,插到key2列表左边
7LINDEX key index 通过索引获取列表中的元素
8LLEN key 获取列表长度
9LINSERT key BEFORE|AFTER value new_value 在列表的元素前或者后插入元素
10LREM key count value 移除列表元素,从左边开始删除count个元素
11LSET key index value 通过索引设置列表元素的值,会覆盖原有的值
4.3 Redis集合(Set)

特征:无序的,唯一的

Redis set对外提供的功能与list类似,是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择。

Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。它的内部使用hash结构,所有的value都指向同一个内部值,类似于Java中HashSet。

序号命令及描述
1SADD key member1 member2向集合添加一个或多个成员
2SMEMBERS key 返回集合中的所有成员
3SISMEMBER key member 判断 member 元素是否是集合 key 的成员
4SCARD key 获取集合的成员数
5SREM key member1 移除集合中一个或多个成员
6SPOP key 移除并返回集合中的一个随机元素
7SRANDMEMBER key count 返回集合中一个或多个随机数
8SINTER key1 key2 返回第一个集合与第二个集合之间的交集
9SUNION key1 key2 返回第一个集合与第二个集合之间的并集
10SDIFF key1 key2 返回第一个集合与第二个集合之间的差异 【key1中,不包含key2中】

 

4.4 Redis哈希(Hash)

Redis hash 是一个 string 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储对象。

key: 字符串名称

value:放一个对象

序号命令及描述
1HSET key field value 将哈希表 key 中的字段 field 的值设为 value 例如:hset users name zhangsan
2HGET key field 获取存储在哈希表中指定字段的值。例如: hget users name
3HMSET key field1 value1 field2 value2 同时将多个 field-value (域-值)对设置到哈希表 key 中。
4HEXISTS key field 查看哈希表 key 中,指定的字段是否存在。
5HKEYS key 获取所有哈希表中的字段(键)。
6HVALS key 获取哈希表中所有值。
7HINCRBY key field increment 为哈希表 key 中的指定字段的整数值加上增量 increment 。
8HSETNX key field value 只有在字段 field 不存在时,设置哈希表字段的值。

4.5 Redis有序集合(Zset)

Redis 有序集合和集合一样也是 string 类型0元素的集合,且不允许重复的成员。

特征:有序的,唯一的

不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。

有序集合的成员是唯一的,但分数(score)却可以重复。

序号命令及描述
1ZADD key score1 member1 score2 member2向有序集合添加一个或多个成员,或者更新已存在成员的分数 例如:zadd topn 100 java 200 mysql 300 linux 400 c 500 redis
2ZRANGE key start stop 通过索引区间返回有序集合指定区间内的成员 例如:zrange topn 0 -1 withscores
3ZRANGEBYSCORE key min max [WITHSCORES] LIMIT通过分数返回有序集合指定区间内的成员
4ZREVRANGEBYSCORE key max min 返回有序集中指定分数区间内的成员,分数从高到低排序
5ZINCRBY key increment member 有序集合中对指定成员的分数加上增量 increment
6ZREM key member 移除有序集合中的一个或多个成员
7ZCOUNT key min max 计算在有序集合中指定区间分数的成员数
8ZRANK key member 返回有序集合中指定成员的索引

5. SpringBoot整合Redis

Spring Boot整合Redis提供了 RedisTemplate与StringRedisTemplate两个类,其中StringRedisTemplate是RedisTemplate的子类,两个方法基本一致,不同之处主要体现在操作的数据类型不同,RedisTemplate中两个泛型都是Object,意味着存储的key和value都可以是一个对象,而StringRedisTemplate的两个泛型都是String,意味着StringRedisTemplate的key和value都只能是字符串。

StringRedisTemplate<String,String>

RedisTemplate<Object,Object>
5.1 引入redis依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
5.2 配置设置
spring:
  redis:
    host: 192.168.2.167
    port: 6379
    password: 123456
    database: 0
5.3 StringRedisTemplate应用

StringRedisTemplate主要应用于键和值都是String的情况

创建测试类测试:

package com.example.springredis;
​
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
​
@SpringBootTest
class SpringRedisApplicationTests {
​
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    
    @Test
    public void test1(){
        Set<String> keys = stringRedisTemplate.keys("*");
        keys.forEach(System.out::println);
    }
}

5.3.1 操作Keys

直接使用stringRedisTemplate,点方法就可以

stringRedisTemplate.type("name");  //获取类型
stringRedisTemplate.delete("name"); //删除指定key
stringRedisTemplate.hasKey("name");//判断key是否存在
stringRedisTemplate.getExpire("name");//查看过期时间 -1 代表永不超时 -2 代表过期 
5.3.2 操作String

使用stringRedisTemplate.opsForValue()操作的就是字符串类型

stringRedisTemplate.opsForValue().set("gender","女");
String gender = stringRedisTemplate.opsForValue().get("gender");
System.out.println(gender);
//设置一个key超时时间
stringRedisTemplate.opsForValue().set("code","000098",120, TimeUnit.SECONDS);
5.3.3 操作List

使用stringRedisTemplate.opsForList()操作的就是list类型

stringRedisTemplate.opsForList().leftPush("names","张三");
stringRedisTemplate.opsForList().leftPushAll("names","张三","李四","王五");
List<String> list=new ArrayList<>();
list.add(0,"老大");
list.add(1,"老二");
list.add(2,"老三");
stringRedisTemplate.opsForList().leftPushAll("names",list);
List<String> names = stringRedisTemplate.opsForList().range("names", 0, -1);
names.forEach(System.out::println);
5.3.4 操作Set

使用stringRedisTemplate.opsForSet()操作的就是set类型

stringRedisTemplate.opsForSet().add("userNames","张三","张三","李四","王五");
Set<String> userNames = stringRedisTemplate.opsForSet().members("userNames");
Long size = stringRedisTemplate.opsForSet().size("userNames");
System.out.println(size);
userNames.forEach(System.out::println);
5.3.5操作zSet

使用stringRedisTemplate.opsForZSet()操作的就是zSet类型

stringRedisTemplate.opsForZSet().add("zsets", "java", 500);
stringRedisTemplate.opsForZSet().add("zsets", "spring", 200);
stringRedisTemplate.opsForZSet().add("zsets", "redis", 300);
Set<String> zsets = stringRedisTemplate.opsForZSet().range("zsets", 0, -1);
zsets.forEach(System.out::println);
System.out.println("========================");
​
Set<ZSetOperations.TypedTuple<String>> zsets1 = stringRedisTemplate.opsForZSet().rangeByScoreWithScores("zsets",200,500);
zsets1.forEach(item -> {
    System.out.println("item"+item);
    System.out.println(item.getValue());
    System.out.println(item.getScore());
});
5.3.6操作Hash

使用stringRedisTemplate.opsForHash()操作的就是hash类型

stringRedisTemplate.opsForHash().put("maps","name","张三");
Object o = stringRedisTemplate.opsForHash().get("maps", "name");
System.out.println(o);
Set<Object> name = stringRedisTemplate.opsForHash().keys("maps");
name.forEach(System.out::println);
List<Object> maps = stringRedisTemplate.opsForHash().values("maps");
maps.forEach(System.out::println);

5.4 RedisTemplate应用

RedisTemplate主要应用于存储的值是对象的情况,但如果使用对象,所有的对象都必须进行序列化才可以存储。

RedisTemplate存储的时候会对键和值进行序列化操作。

5.4.1 操作普通对象
User u1 = new User("zs", 20, "15386880458");
redisTemplate.opsForValue().set("u1", u1);
User user =(User) redisTemplate.opsForValue().get("u1");
System.out.println(user);
5.4.2 操作List
@Test
public void test2() {
    User u1 = new User("zs", 20, "15386880458");
    User u2 = new User("lisi", 20, "15386880458");
    redisTemplate.opsForList().leftPush("users",u1);
    redisTemplate.opsForList().leftPush("users",u2);
    List userlist = redisTemplate.opsForList().range("users", 0, -1);
    userlist.forEach(System.out::println);
​
}
5.4.3 操作Hash
@Test
public void test4() {
    User u1 = new User(100, "lxd", 20);
    User u2 = new User(101, "cdp", 21);
    User u3 = new User(102, "luhui", 21);
    List<User> list = new ArrayList<>(); //从数据库中获取到集合数据
    list.add(u1);
    list.add(u2);
    list.add(u3);
    redisTemplate.opsForHash().put("data", "userList", list);
    List<User> userList = (List<User>) redisTemplate.opsForHash().get("data", "userList");
    for (User user : userList) {
        System.out.println(user);
    }
}

6. 自定义Template

springboot项目整合Redis记录了RedisTemplate和StringRedisTemplate的使用效果,由于分别使用了不同的序列化器,所以在Redis中存储的形式也不相同。redisTemplate使用的是默认的序列化器jdk序列化方式,而StringRedisTemplate使用了String序列化方式,如果使用默认的这种序列化方式,存入redis中的key就变成带有转义字符的,这种情况就可以自定义RedisTemplate类,一般为了开发的方便,直接定义RedisTemplate<String, Object>类型,配置内容如下,企业实际开发中,直接可以使用:

使用的依赖,springboot已经集成,无需再导入

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>

配置类:

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
​
@Configuration
public class RedisConfig {
​
    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        //自定义Jackson序列化配置
        Jackson2JsonRedisSerializer jsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
        jsonRedisSerializer.setObjectMapper(objectMapper);
​
        //key使用String的序列化方式
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        template.setKeySerializer(stringRedisSerializer);
        //hash的key也是用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        //value的key使用jackson的序列化方式
        template.setValueSerializer(jsonRedisSerializer);
        //hash的value也是用jackson的序列化方式
        template.setHashValueSerializer(jsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
​
    }
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值