Redis 基础详细介绍(Redis简单介绍,命令行客户端,Redis 命令,Java客户端)
1. Redis 简介
Redis(Remote Dictionary Server)是一个开源的内存数据库,遵守 BSD 协议,它提供了一个高性能的键值(key-value)存储系统,常用于缓存、消息队列、会话存储等应用场景。
1.1 特征
-
丰富的数据类型:Redis 不仅仅支持简单的 key-value 类型的数据,还提供了 list、set、zset(有序集合)、hash 等数据结构的存储。这些数据类型可以更好地满足特定的业务需求,使得 Redis 可以用于更广泛的应用场景。
-
高性能的读写能力:Redis 能读的速度是 110000次/s,写的速度是 81000次/s。这种高性能主要得益于 Redis 将数据存储在内存中,从而显著提高了数据的访问速度。
-
原子性操作:Redis 的所有操作都是原子性的,这意味着操作要么完全执行,要么完全不执行。这种特性对于确保数据的一致性和完整性非常重要。
-
持久化机制:Redis 支持数据的持久化,可以将内存中的数据保存在磁盘中,以便在系统重启后能够再次加载使用。这为 Redis 提供了数据安全性,确保数据不会因为系统故障而丢失。
-
丰富的特性集:Redis 还支持 publish/subscribe(发布/订阅)模式、通知、key 过期等高级特性。这些特性使得 Redis 可以用于消息队列、实时数据分析等复杂的应用场景。
-
主从复制和高可用性:Redis 支持 master-slave 模式的数据备份,提供了数据的备份和主从复制功能,增强了数据的可用性和容错性。
-
支持 Lua 脚本:Redis 支持使用 Lua 脚本来编写复杂的操作,这些脚本可以在服务器端执行,提供了更多的灵活性和强大的功能。
-
单线程模型:尽管 Redis 是单线程的,但它通过高效的事件驱动模型来处理并发请求,确保了高性能和低延迟。
1.2 SQL 和 NOSQL 区别
Redis 属于 NOSQL 类型
- 结构化:数据库表的字段的类型即长度都是限定好的。
- SQL查询:SQL 查询语句格式是固定的无论 MySql 还是 Oracle
- ACID:原子性,一致性,隔离性,持久性
- BASE:不全部满足 ACID
- 关联:数据表中的数据可以通过外键关联在一起
2. Redis 命令行客户端
Redis 安装完成后就自带了命令行客户端:redis-cli,使用方式如下:
// 先输入
redis-cli -h 127.0.0.1 -p 6379
// 回车后输入
auth 123456
其中常见的 options 有:
-h 127.0.0.1
:指定要连接的 redis 节点的 IP 地址,默认是 127.0.0.1 (本机),也可以填写本机的 IP 地址-p 6379
:指定要连接的 redis 节点的端口,默认是 6379-a 123456
:指定 redis 的访问密码 (一般不这个,使用auth
命令来输入密码)
3. Redis 数据结构介绍
4. Redis 命令
对于这些命令 Redis 都提供了帮助文档只要在你要使用的命令前面加入 help 即可
4.1 通用命令
-
KEYS
查看符合模板的所有 key,不建议在生成环境设备上使用
KEYS pattern
-
DEL
删除一个指定的 Key
DEL key [key ...]
-
EXISTS
判断 Key 是否存在
EXISTS key [key ...]
-
EXPIRE
给一个 Key 设置有效期,有效期到了该 Key 自动删除
EXPIRE key seconds
-
TTL
查看一个 Key 剩余的有效期
TTL key
-
hlep
查看某个命令的使用方法
help del
4.2 String类型命令
4.2.1 String类型分类
- 字符串
- 整形(Int)
- 浮点型(Float)
4.2.2 常用命令
-
SET
添加或者修改,指定键不存在则新增,否则修改
set name jack
-
GET
根据 key 获取 String 类型的 Value
get name
-
MSET
批量添加 String 类型的键值对
mset key1 value1 key2 value2
-
MGET
根据多个 Key 获取多个 Value
mget key1 key2
-
INCR
让一个整形的 key 的值自增 1
incr age
-
INCRBY
让一个整形 key 自增并指定步长
incrby num 2
-
INCRBYFLOAT
让一个浮点类型的值自增并指定步长
incrbyfloat num 0.2
-
SETNX
添加一个 String 类型的键值对前提是这个 Key 不存在,否则不执行
setnx name jack
-
SETEX
添加一个键值对,并指定有效日期。
setex name 10 jack
4.3 Key的层级格式
在 Redis 没有类似于 MySQL 中 Table 的概念,我们如何区分不同类型 Key 呢?
比如我们需要存储商品信息和用户信息到 Redis 当中,此时他们的 Id 恰好都为 1。这样当我们要取数据时发现无法区分。此时我们可以给 Key 加上一个前缀加以区分。当然这前缀按规范要具有一定层次结构
4.4 Hash类型命令
该结构类似于 Java 的 HashMap
4.4.1 哈希类型结构
4.4.2 常见命令
-
HSET key field value
添加或者修改 Hash 类型,键为 key ,值的键为 field 的值为 Value
hset user name zhansan
-
HGET key field
根据 key 获取 Hash 类型,键为 key ,值的键为 field 的值
hget user name
-
HMSET
批量添加 Hash 类型 Key 的 field 的值
hset user name zhansan age 18
-
HMGET
批量获取 Hash 类型,键为 key 的多个 field 的值
hmget user name age
-
HGETALL
获取一个 Hash 类型,键为 key 所有的键值对
hgetall user
-
HKEYS
获取一个 Hash 类型,键为 key 所有的键
hkeys user
-
HVALS
获取一个 Hash 类型,键为 key 所有的值
hvals user
-
HINCRBY
让一个 Hash 类型的 key 的 field 的值自增长指定步长
hincrby user age 2
-
HSETNX
添加一个 Hash 类型的 key 的 field 的值,前提是这个 field 不存在,否则不执行
hsetnx user age 100
4.5 List类型
类似双端队列,查询慢,删除快,该数据类型可以根据方法,模拟栈,队列,阻塞队列的数据结构
4.5.1 常见命令
-
LPUSH key element
向列表左侧插入一个或者多个元素
lpush goods car food
-
RPUSH key element
向列表右侧插入一个或者多个元素
rpush goods car food
-
RPOP KEY [COUNT]
将列表左侧元素弹出一个或者多个,没有则返回 nil
lpop goods 2
-
RPOP KEY
将列表右侧元素弹出一个或者多个,没有则返回 nil
rpop goods 2
-
BLPOP 和 BRPOP [TimeOut]
和 LPOP 和 RPOP 类似,只不过在当列表中没有元素的时候会等待指定时间,而不是返回nil,后面该功能会被充当缓冲队列
Brpop user 10
-
LRANGE KEY STAR END
返回一段角标内的所有元素
4.6 Set类型
无序,不重复,查询快,类似于 C++ 的 Unordered_Set
4.6.1 常见命令
-
SADD key member
向指定 Key 的集合中插入一个或者多个元素
-
SREM key member
将指定 Key 的集合中指定元素删除
-
SCARD key
统计集合中的元素
-
SISMEMBER key member
查询某个元素是否在集合当中
-
SMEMBERS key:
获取指定Key的集合中的所有元素
-
SINTER key1 key2
获取键为 key1 和 key2 两个集合的交集
-
SDIFF key1 key2
获取键为 key1 和 key2 两个集合的差集
-
SUNION key1 key2
获取键为 key1 和 key2 两个集合的并集
4.7 SortedSet类型
可排序集合和 Java 中的 TreeSet 类似,但底层差距很大。SortedSet中的每个元素都带有一个score属性,可以基于 score 的值对集合进行排序,底层实现是 跳表 + hash表 。常被用于实现排行榜的业务。
4.7.1 常用命令
-
ZADD key score member
添加一个或者多个元素,score 是加入元素的分数(排序依据),member 表示要加入的元素
-
ZREM key member
删除指定元素
-
ZSCORE key member
获取指定元素的分数
-
ZRANK key member
获取指定元素的排名(默认升序排名,可以用 ZREVRANK 获取降序排名)
-
ZCARD key
获取集合中的元素数量
-
ZCOUNT key min max
统计 Score 值在 min 和 max 之间的元素个数
-
ZINCRBY key increment member
让集合指定元素 member 自增,步长为指定的 increment 的值
-
ZRANGE key min max
按照 Score 排序后,获取指定排名范围内的元素
-
ZRANGEBYSCORE key min max
按照 Score 排序后,获取指定分数范围内的元素
-
ZDIFF,ZINTER,ZUNION
求差集,求交集,求并集。
5. Java客户端
5.1 简介
Java的Redis客户端(如Jedis、Lettuce)通过封装Redis协议,允许Java应用与Redis服务器交互。它们提供直观的API执行数据操作,支持连接池、集群、哨兵等部署模式。其中Jedis轻量高效但线程不安全,需配合连接池使用;Lettuce基于Netty实现异步与线程安全;Redisson专注分布式服务。开发者可根据性能、线程模型和功能需求灵活选用。
5.2 Jedis
5.2.1 简介
Jedis 是一款轻量级、同步阻塞的 Java Redis 客户端,通过直连模式与 Redis 服务器通信。其 API 直接映射 Redis 原生命令(如
set()
对应SET
指令),学习成本低且稳定性强;但原生线程不安全(多线程需依赖连接池),适用于并发要求不高的传统项目或小型应用,是 Java 生态中最经典的 Redis 集成方案之一。
5.2.2 特点
-
优点:
Jedis 设计小巧,实现简洁,稳定性高。其最大优势在于 API 与 Redis 原生命令高度一致:方法名和参数直接对应官方文档指令。这使得开发者遇到不熟悉的操作时,无需额外学习客户端封装,直接查阅 Redis 命令文档即可快速上手,显著降低了学习成本。相比之下,某些客户端重命名 API 的做法虽意图简化,实则增加了额外的记忆负担。 -
缺点:
Jedis 采用直连模式且非线程安全。其核心问题在于:单个Jedis
实例内的RedisOutputStream
(写流) 和RedisInputStream
(读流) 是共享的全局资源。当多个线程并发操作同一实例时,会争抢这些流资源,导致读写数据混乱(如数据错位、混合),而非 Redis 服务本身的数据安全问题。
5.2.3 Jedis 的使用
- 引用依赖
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.7.0</version>
</dependency>
- 建立连接
private Jedis jedis;
@Before // 该注解,表示在所有你创键的测试方法前先执行,这里用于建立连接
public void setUp() throws Exception {jedis = new Jedis("192.168.195.132", 6379); //建立连接jedis.auth("123456"); //密码jedis.select(0); //选择库
}
- 使用 Jedis
@Test
public void testString() {//命令名和 Redis 的一致 String s = jedis.set("name", "tom");String name = jedis.get("name");
}
- 释放资源
@After // 该注解,表示在所有你创键的测试方法后执行,这里用于关闭连接
public void tearDown() throws Exception {// 如果在建立连接的时候抛出了异常,那么运行到这的时就会有空指针异常的风险if(jedis != null) {jedis.close();}
}
5.2.4 Jedis连接池
Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗。所以建议使用 Jedis 的连接池来代替 Jedis的直连方式。
public class JedisConnectionFactory {private static JedisPool jedisPool;static {//配置连接池JedisPoolConfig poolConfig = new JedisPoolConfig();//最大连接量,表示最多建立8个连接poolConfig.setMaxTotal(8); //最大空闲连接,表示即便没有线程访问我这个池子,也会最多预备8个连接poolConfig.setMaxIdle(8); //最小空闲连接,表示空闲连接存放一段时间后,会被自动释放,直到预备连接小于等于2个poolConfig.setMinIdle(2); //最长等待时间,表示当连接池内没有空闲连接时,线程对多等多久后放弃等待poolConfig.setMaxWaitMillis(1000); //建立连接jedisPool = new JedisPool(poolConfig,"192.168.195.132", 6379, 1000, "123456");}// 获取连接public static Jedis getJedis() {return jedisPool.getResource();}
}
5.3 SpringDataRedis
5.3.1 简介
- Spring Data Redis 是 Spring 生态的 Redis 集成框架,内部整合来 Jedis 和 Lettuce。
- 提供了
RedisTemplate
统一 API 来操作 Redis。- 简化数据操作(自动处理序列化/连接管理)
- 支持事务、发布订阅、集群与哨兵模式,并天然适配 Spring 事务管理,显著降低 Java 应用访问 Redis 的复杂度,适用于需与 Spring 深度整合的中大型项目。
5.3.2 SpringDataRedis的使用
**SpringBoot 已经整合 SpringDataRedis,并且实现了自动装配,使用起来非常方便,**所以下面我们基于SpringBoot 来使用 SpringDataRedis
- 引入依赖
<!--redis起步依赖-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency><!--连接池依赖-->
<!--无论是 Jedis 还是 Luttce,都是基于 commons-pool 来实现连接池的效果 -->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>
- 连接和连接池配置
spring:data:redis:host: 192.168.195.132 #连接的虚拟机的 IP 地址port: 6379 #端口号database: 0 #连接的数据库password: 123456 #密码lettuce:pool: #连接池的配置max-active: 8 #最大连接数max-idle: 8 #最大空闲连接数min-idle: 0 #最小空闲连接数max-wait: 100ms #最大等待时间#具体解释可以看 Jedis 配置连接池那一节
- 测试代码
@SpringBootTest
class RedisDemoApplicationTests {@Autowiredprivate RedisTemplate redisTemplate;@Testvoid stringTest() {redisTemplate.opsForValue().set("name", "虎哥");Object name = redisTemplate.opsForValue().get("name");System.out.println(name);}
}
5.3.3 RedisTemplated的缺点
RedisTemplate 可以存储任意类型的数据,原因是在存储之前会先把存储的数据序列化字节形式,默认采用的 JDK 序列化。但是得到的结果,可读性差,并且占用了更多的内存
5.3.3 解决方式
RedisTemplate 的缺点产生原因在于他默认的序列化方式不太合适,所以我们可以更改他的序列化方式即可解决这个问题。
存在的小问题以及解决办法
- 但是这种方式还是存在一点点问题就是,他 Value 使用的是 Json 序列化器,当存入和获取的数据类型是对象是会自动序列化和反序列化,但是要实现自动反序列化,存入 Redis 的数据数据需要加一段额外的信息来记录该 Json 数据属于哪个对象,这样就造成了,内存的额外开销。
- 解决方式也很简单,就是再一次跟换 Value 的序列化方式,采用和 Key 一样的 String 序列化器,但是后果就是,存入数据类型只能是 String 类型。但是没关系,只要当我们要存入对象时,就先将他转为 Json 字符串格式
- 但是幸运的是我们不要自己再去修改,RedisTemplate 的 Value 的序列化方式了。这个别人已经写好了。Spring 提供了一个 StringRedisTemplate 类,他的 Key 和 Value 默认的序列化方式就是 String 序列化,省去了我们自己定义 RedisTemplate。
5.3.4 StringRedisTemplate
5.3.4.1 简介
为了节省空间我们并不会使用 Json 的序列化器来处理 value,而是统一的使用 String 的序列化器,要求只能存储String 类型的 key 和 value。当需要存储 Java 对象的时候,需手动完成对象序列化和反序列化。
5.3.4.2 使用步骤
至于序列化工具,使用自己喜欢的就好,我这里使用的 FastJson
- 导入依赖
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.7</version>
</dependency>
- 代码演示
@Autowired
private StringRedisTemplate stringRedisTemplate;@Test
void objectTest() {User user = new User("name", "虎哥");//手动序列化(object -> Json)String s = JSON.toJSONString(user);stringRedisTemplate.opsForValue().set("user:100", s);String s1 = stringRedisTemplate.opsForValue().get("user:100");//手动反序列化(Json -> object)User user1 = JSON.parseObject(s1, User.class);System.out.println(user1);
}