redis基础篇

一、Redis快速入门

1.1 初识redis

1.1.1 认识NoSql

  • Sql -> 关系型数据库

    • 结构化(Structured) -> 对于表中的数据,我们可以进行约束,如主键约束,长度约束等。
    • 关联的(Relational) -> 表和表之间可以通过某个字段进行关联,如有user用户表和product商品表,有一个order表将这两个表的id关联起来,此时order表存入user的id和product的id,并不用存整个user数据。
    • SQL查询 -> 共用查询语句,不同的关系型数据库都适用。
    • ACID -> 原子性(atomicity,或称不可分割性)、一致性(consistency)、隔离性(isolation,又称独立性)、持久性(durability)。
  • NoSql -> 非关系性数据库

    • 非结构化
    • 无关联的
    • 非sql查询
    • BASE -> BA基本可用,S允许中间态,E最终一致性

    在这里插入图片描述

1.1.2 认识redis

​ Redis诞生于2009年全称是Remote Dictionary Server,远程词典服务器,是一个基于内存的键值型NoSQL数据库。

  • 特征:
    • 键值(key-value) 型,value支持多种不同数据结构,功能丰富
    • 单线程,每个命令具备原子性。redis6.0多线程仅仅对于网络请求处理这部分,核心命令执行依然是单线程
    • 低延迟,速度快(基于内存、IO多路复用、良好的编码)
    • 支持数据持久化
    • 支持主从集群(从节点可以备份主节点的数据,可以进行读写分离,提高效率)、分片集群(如将1TB数据存在不同节点上,存储上限提高)
    • 支持多语言客户端(java,python,C等等)

1.2 安装Redis

1.2.1 安装redis依赖

Redis是基于C语言编写的,因此首先需要安装Redis所需要的gcc依赖:

yum install -y gcc tcl

1.2.2 上传安装包

然Redis安装包上传到虛拟机的任意目录:如/usr/local/src目录

进入目录解压缩:

tar -zxvf redis-6.2.6.tar.gz

进入redis目录:

cd redis-6.2.6

运行编译命令,make代表编译,make install代表安装:

make && make install

如果没有出错就是安装成功,默认安装路径在/usr/local/bin目录下

  • 切换到该目录下查看:
    • 该目录以及默认配置到环境变量,因此可以在任意目录下运行这些命令。其中:
      • redis-cli: 是redis提供的命令行客户端
      • redis-server: 是redis的服务端启动脚本
      • redis-sentinel: 是redis的哨兵启动脚本

1.2.3 启动

  • redis的启动方式有很多种,例如:

    • 默认启动
    • 指定配置启动
    • 开机自启
  • 默认启动:安装完成后,在任意目录输入redis-server命令即可启动Redis:

redis-server

这种启动属于[前台启动],会阻塞整个会话窗口,窗口关闭或者按下( CTRL + C )则Redis停止。不推荐使用。

  • 指定配置启动

如果要让Redis以后台]方式启动,则必须修改Redis配置文件,就在我们之前解压的redis安装包下
([/usr/local/src/redis-6.2.6)) ,名字叫redis.conf:

我们先将这个配置文件备份一份(怕弄错了好恢复):

cp redis.conf redis.conf.bck

这时我们就可以修改redis.conf文件:

vim redis.conf

准备修改redis.conf文件中的一些配置:

#监听的地址,默认是127.0.0.1, 会导致只能在本地访问。修改为0. 0.0.0则可以在任意IP访问,生产环境不要设置为0.0.0.0
bind 0.0.0.0
#守护进程,修改为yes后即可后台运行
deamonize yes
#密码,设置后访问Redis必须输入密码
requirepass 123456

Redis的其它常见配置:

#监听的端口
port 6379
#工作目录,默认是当前目录,也就是运行redis-server时的命令, 日志、持久化等文件会保存在这个目录
dir . 
#数据库数量,设置为1,代表只使用1个库,默认有16个库,编号0~15
databases 1
#设置redis 能够使用的最大内存
maxmemory 512mb
#日志文件,默认为空,不记录日志,可以指定日志文件名
logfile "redis.log"

现在我们开始修改配置:

  • 修改第一处:

在这里插入图片描述

  • 修改第二处:

在这里插入图片描述

  • 修改第三处

在这里插入图片描述

  • 后面的根据需求改,也可以加个日志:

在这里插入图片描述

这时可以启动:

cd /usr/local/src/redis-6.2.6
redis-server redis.conf
# 查看进程
ps -ef | grep redis

停止服务:

redis-cli -a 123456 shutdown

1.2.4 设置开机自启

  • 编辑文件
vi /etc/systemd/system/redis.service
  • 编辑内容如下:
[Unit]
Description=redis-server
After=network.target

[Service]
Type= forking 
ExecStart=/usr/local/bin/redis-server /usr/local/src/redis-6.2.6/redis.conf
PrivateTmp=true


[Install]
WantedBy=multi-user.target

  • 然后重载系统服务:
systemctl daemon-reload
# 启动redis
systemctl start redis
# 查看redis状态
systemctl status redis
# 停止redis
systemctl stop redis
# 此时没啥问题就可以设置开机自启了
systemctl enable redis

1.3 redis命令行客户端

Redis安装完成后就自带了命令行客户端:redis-cli,使用方式如下:

redis-cli [option] [command]
  • 其中常见的options有:

    • -h 127.0.0.1 :指定要连接的redis节点的IP地址,默认是127.0.0.1
    • -p 6379 :指定要连接的redis节点的端口,默认是6379
    • -a 123456 : 指定redis的访问密码
  • 其中的commonds就是Redis的操作命令,例如:

    • ping:与redis服务端做心跳测试,服务端正常会返回pong
    • 不指定commond时,会进入redis-cli 的交互控制台:

在这里插入图片描述

连接上后会有这个警告,此时可以我们先进入,再输入密码

在这里插入图片描述

这时候就没有警告了

二、redis常用命令

2.1 redis数据结构介绍

Redis是一个key-value的数据库,key一般是String类型,不过value的类型多种多样:

在这里插入图片描述

2.2 redis结构及命令

2.2.1 通用命令

  • 通用指令是部分数据类型的,都可以使用的指令,常见的有:
    • KEYS:查看符合模板的所有key,不建议在生产环境设备上使用
    • DEL:删除一个指定的key
    • EXISTS: 判断key是否存在
    • EXPIRE: 给一个key设置有效期,有效期到期时该key会被自动删除
    • TTL:查看一个KEY的剩余有效期

2.2.2 String类型

  • String类型,也就是字符串类型,是Redis中最简单的存储类型。其value是字符串,不过根据字符串的格式不同,又可以分为3类:

    • string: 普通字符串
    • int: 整数类型,可以做自增、自减操作
    • float: 浮点类型,可以做自增、自减操作
  • 不管是哪种格式,底层都是字节数组形式存储,只不过是编码方式不同。字符串类型的最大空间不能超过512m.

  • String常见命令:

    • SET:添加或者修改已经存在的一个String类型的键值对,SET会覆盖之前同样KEY的值 SET K1 V1
    • GET:根据key获取String类型的value GET K1
    • MSET:批量添加多个String类型的键值对 MSET K1 V1 K2 V2 K3 V3
    • MGET:根据多个key获取多个String类型的value MGET K1 K2 K3
    • INCR:让一个整型的key自增1 INCR age
    • INCRBY:让一个整型的key自增并指定步长,例如: incrby num 2让num值自增2 INCRBY age 2
    • INCRBYFLOAT:让一个浮点类型的数字自增并必须指定步长 INCRBYFLOAT score 0.5
    • SETNX:添加一个String类型的键值对,前提是这个key不存在,否则不执行 SETNX K1 V1
    • SETEX:添加一个String类型的键值对,并且指定有效期 SETEX K1 V1 10

2.2.3 key的层级格式

如果我们有一个user的id为1,product的id为1,那么怎么办呢?

  • Redis的key允许有多个单词形成层级结构,多个单词之间用"隔开,格式如下:项目名:业务名:类型:id

  • 这个格式并非固定,也可以根据自己的需求来删除或添加词条。例如我们的项目名称叫shop,有user和product两种不同类型的数据,我们可以这样定义key:

    • user相关的key: shop:user:1
    • product相关的key: shop:product:1
  • 如果Value是一个Java对象,例如一个User对象,则可以将对象序列化为JSON字符串后存储

KEYVALUE
shop:user:1{“id”:1, “name”:“jack”,“age”:21}
shop:product:1{“id”:1,“name”:“iPhone”,“price”:5999}

2.2.4 Hash 类型

  • Hash类型,也叫散列,其value是一个无序字典,类似于Java中的HashMap结构。

  • String结构:是将对象序列化为JSON字符串后存储,当需要修改对象某个字段时很不方便

  • Hash结构可以将对象中的每个字段独立存储,可以针对单个字段做CRUD:

  • Hash常见的命令有:

    • HSET key field value:添加或者修改hash类型key的field的值
    • HGET key field:获取一个hash类型key的field的值
    • HMSET:批量添加多个hash类型key的field的值
    • HMGET:批量获取多个hash类型key的field的值
    • HGETALL:获取一个hash类型的key中的所有的field和value
    • HKEYS:获取一个hash类型的key中的所有的field
    • HVALS:获取一个hash类型的key中的所有的value
    • HINCRBY:让一个hash类型key的字段值自增并指定步长
    • HSETNX:添加一个hash类型的key的field值,前提是这个field不存在,否则不执行

2.2.5 List类型

  • Redis中的List类型与Java中的LinkedList类似,可以看做是一个双向链表结构。既可以支持正向检索和也可以支持反向检索。特征也与LinkedList类似:

    • 有序
    • 元素可以重复
    • 插入和删除快
    • 查询速度一般
  • 常用来存储一个有序数据,例如:朋友圈点赞列表,评论列表等。

  • List的常见命令有:

    • LPUSH key element… :向列表左侧插入一个或多个元素
    • LPOP key:移除并返回列表左侧的第一个元素,没有则返回nil
    • RPUSH key element… :向列表右侧插入一个或多个元素
    • RPOP key:移除并返回列表右侧的第一 -个元素
    • LRANGE key star end:返回一段角标范围内的所有元素
    • BLPOP和BRPOP:与LPOP和RPOP类似,只不过在没有元素时等待指定时间,而不是直接返回nil
  • 思考:

    • 如何利用List结构模拟一个栈?
      • 先进后出,入口和出口在同一边,所以使用 LPUSH,LPOP或者RPUSH,RPOP就可以了
    • 如何利用List结构模拟一个队列?
      • 先进先出,入口和出口在不同边,所以使用 LPUSH,RPOP或者LPUSH,RPOP就可以了
    • 如何利用List结构模拟一个阻塞队列?
      • 入口和出口在不同边、出队时采用BLPOP或BRPOP

2.2.6 Set类型

  • Redis的Set结构与Java中的HashSet类似,可以看做是一个value为 null的HashMap。因为也是一个hash表, 因此具备与HashSet类似的特征:

    • 无序
    • 元素不可重复
    • 查找快
    • 支持交集、并集、差集等功能
  • set常用命令有:

    • SADD key member … :向set中添加一个或多个元素

    • SREM key member … :移除set中的指定元素

    • SCARD key:返回set中 元素的个数

    • SISMEMBER key member:判断一个元素是否存在于set中

    • SMEMBERS:获取set中的所有元素

    • SINTER key1 key2… :求key1与key2的交集

    • SDIFF key1 key2 … :求key1与key2的差集

    • SUNION key1 key2 …:求key1和key2的并集

2.2.7 SortedSet 类型

  • Redis的SortedSet是一个可排序的set集合,与Java中的TreeSet有些类似,但底层数据结构却差别很大。SortedSet中的每一个元素都带有一个score属性,可以基于score属性对元素排序,底层的实现是一个跳表(SkipList) 加hash表。SortedSet具备下列特性:

    • 可排序

    • 元素不重复

    • 查询速度快

  • 因为SortedSet的可排序特性,经常被用来实现排行榜这样的功能。

  • SortedSet常用命令有:

    • ZADD key score member:添加一个或多个元素到sorted set ,如果已经存在则更新其score值
    • ZREM key member:删除sorted set中的一个指定元素
    • ZSCORE key member :获取sorted set中的指定元素的score值
    • ZRANK key member:获取sorted set中的指定元素的排名
    • ZCARD key:获取sorted set中的元素个数
    • ZCOUNT key min max:统计score值在给定范围内的所有元素的个数
    • ZINCRBY key increment member:让sorted set中的指定元素自增,步长为指定的increment值
    • ZRANGE key min max:按照score排序后,获取指定排名范围内的元素
    • ZRANGEBYSCORE key min max:按照score排序后,获取指定score范围内的元素
    • ZDIFF、ZINTER、ZUNION:求差集、交集、并集
  • 注意:所有的排名默认都是升序,如果要降序则在命令的Z后面添加REV即可

三、redis的java客户端

3.1 客户端对比

Jedis以Redis命令作为方法名称,学习成本低,简单实用。但是Jedis实例是线程不安全的,多线程环境下需要基于连接池来使用
lettuceLettuce是基于Netty实现的,支持同步、异步和响应式编程方式,并且是线程安全的。支持Redis的哨兵模式、集群模式和管道模式。
RedissonRedisson是一个基于Redi s实现的分布式、可伸缩的Java数据结构集合。包含了诸如Map、Queue、Lock、Semaphore、AtomicLong等强大功能

3.2 Jedis快速入门

首先我们引入依赖:

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>4.3.1</version>
</dependency>
//导入junit-jupiter去测试

写测试类:

public class JedisTest {
    private Jedis jedis;
    @BeforeEach
    void setUp(){
        //建立连接
        jedis = new Jedis("192.168.111.112", 6379);
        //设置密码
        jedis.auth("123456");
        //选择库
        jedis.select(0);
    }
    //这个Test类注意是org.junit.jupiter.api.Test;
    @Test
    public void testString(){
        String result = jedis.set("name", "tom");
        System.out.println(result);
        System.out.println(jedis.get("name"));

    }
    @AfterEach
    void tearDown(){
        if (jedis != null){
            jedis.close();
        }
    }
}

3.2.1 jedis-连接池

  • Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此推荐大家使用Jedis连接池代替Jedis的直连方式
//工具类,使用即可
public class JedisConnectionFactory {

    private static final JedisPool jedisPool;
    static {
        //配置连接池
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        //最大连接
        jedisPoolConfig.setMaxTotal(8);
        //最大空闲连接
        jedisPoolConfig.setMaxIdle(8);
        //最小空闲连接
        jedisPoolConfig.setMinIdle(0);
        //等待时长
        jedisPoolConfig.setMaxWait(Duration.ofMillis(1000));
        //创建连接池对象
        jedisPool = new JedisPool(jedisPoolConfig, "192.168.111.112", 6379, 1000, "123456");
    }

    public static Jedis getJedis(){
        return jedisPool.getResource();
    }

}

3.3 Spring Data Redis快速入门

  • SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis

  • 官网地址:

    • 提供了对不同Redis客户端的整合(Lettuce和Jedis )
    • 提供了RedisTemplate统一API来操作Redis
    • 支持Redis的发布订阅模型
    • 支持Redis哨兵和Redis集群
    • 支持基于Lettuce的响应式编程
    • 支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化
    • 支持基于Redis的JDKCollection实现
  • SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中:

API返回值类型说明
redisTemplate.opsForValue()ValueOperations操作String类型数据
redisTemplate.opsForHash()HashOperations操作Hash类型数据
redisTemplate.opsForList()ListOperations操作List类型数据
redisTemplate.opsForSet()SetOperations操作Set类型数据
redisTemplate.opsForZSet()ZSetOperations操作SortedSet类型数据
redisTemplate通用的命令
  • SpringBoot已经提供了对SpringDataRedis的支持,使用非常简单:
<!--首先创建springboot项目,然后引入依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--连接池依赖-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
  • yml配置
spring:
	redis :
		host: 192.168.111.112
		port: 6379
		password: 123456
		lettuce : # spring默认使用lettuce连接池,如果要使用jedis连接池,就要自己导入jedis连接池依赖
			pool :
			max-active: 8 #最大连接
			max-idle: 8 #最大空闲连接
			min-idle: 0 #最小空闲连接
			max-wait: 100 #连接等待时间
  • 然后就可以使用redisTemplate了
@Autowired
private RedisTemplate redisTemplate;
//后面使用就不多写了
  • 但是我们发现一个问题,就是使用redisTemplate.opsForValue().set("name","tom")后,去redis-cli上面去get name,发现并没有这个name,或者这个name并没有被覆盖。输入keys *查看,增加了一个key(看不懂的key),这是什么原因呢?

    • 我们跟进RedisTemplate源码,发现有以下序列化器

    在这里插入图片描述

    • 在以下方法内部初始化序列化器:

在这里插入图片描述

  • 可以看到new JdkSerializationRedisSerializer(...)这个jdk序列化器作为默认的序列化器,所以我们存入的都是序列化后的key和value,所以我们get不到,那么怎么解决这个问题呢

  • 可以看到我们只想让value序列化,key不要序列化,我们可以自定义序列化方式,如下:

	@Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        //创建template
        RedisTemplate<String, Object>  redisTemplate = new RedisTemplate<>();
        //设置连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        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;
    }
  • 我们还要导入Jackson依赖才能使用:
<!--如果有springmvc的依赖,里面自带就不需要引入这个-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>
  • 尽管JSON的序列化方式可以满足我们的需求,但依然存在一些问题,存入键值key-User对象后值的内容如下:
{
	"@class":"com.example.redis.pojo.User",
	"name": "tom",
	"age": 20
}
  • 为了在反序列化时知道对象的类型,JSON序列化器会将类的class类型写入json结果中(就是第一行的数据),存入Redis,会带来额外的内存开销。

  • 为了节省内存空间,我们并不会使用JSON序列化器来处理value,而是统一使用String序列化器,要求只能存储String类型的key和value。当需要存储Java对象时,手动完成对象的序列化和反序列化。

  • Spring默认提供了一个StringRedisTemplate类,它的key和value的序列化方式默认就是String方式。省去了我们自定义RedisTemplate的过程,存入User对象,我们就先序列化,取出的都是String,我们就反序列化。

jackson.core
jackson-databind


- 尽管JSON的序列化方式可以满足我们的需求,但依然存在一些问题,存入键值`key-User对象`后值的内容如下:

```json
{
  "@class":"com.example.redis.pojo.User",
  "name": "tom",
  "age": 20
}
  • 为了在反序列化时知道对象的类型,JSON序列化器会将类的class类型写入json结果中(就是第一行的数据),存入Redis,会带来额外的内存开销。

  • 为了节省内存空间,我们并不会使用JSON序列化器来处理value,而是统一使用String序列化器,要求只能存储String类型的key和value。当需要存储Java对象时,手动完成对象的序列化和反序列化。

  • Spring默认提供了一个StringRedisTemplate类,它的key和value的序列化方式默认就是String方式。省去了我们自定义RedisTemplate的过程,存入User对象,我们就先序列化,取出的都是String,我们就反序列化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值