Redis快速入门
认识NoSQL
什么是NOSQL
- NoSQL最常见的解释是"
non-relational
", 很多人也说它是"Not Only SQL" - NoSQL仅仅是一个概念,泛指非关系型的数据库
- 区别于关系数据库,它们不保证关系数据的ACID特性
- NoSQL是一项全新的数据库革命性运动,提倡运用非关系型的数据存储,相对于铺天盖地的关系型数据库运用,这一概念无疑是一种全新的思维的注入
- 常见的NoSQL数据库有:
Redis
、MemCache
、MongoDB
等
SQL和NoSQL的差别
SQL | No SQL | |
---|---|---|
数据结构 | 结构化 | 非结构化 |
数据关联 | 关联的 | 无关联的 |
查询方式 | SQL查询 | 非SQL |
事务特性 | ACID | BASE |
存储方式 | 磁盘 | 内存 |
扩展性 | 垂直 | 水平 |
使用场景 | 1)数据结构固定 2)相关业务对数据安全性、 一致性要求较高 |
1)数据结构不稳定 2)对一致性、安全性要求不高 3)对性能要求 |
认识Redis
Redis诞生于2009年全称是Remote Dictionary Server,远程词典服务器,是一个基于内存的键值型NoSQL数据库。
Redis的特征:
- 键值(key-value)型,value支持多种不同数据结构,功能丰富。
- 单线程,每个命令具备原子性(新版本网络多线程)。
- 低延迟,速度快(基于内存、IO多路复用、良好的编码)。
- 支持数据持久化
- 支持主从集群、分片集群
- 支持多语言客户端
Redis安装
本次安装基于Mac系统,使用brew进行安装,其他系统以及其他方式可自行百度
redis官网:https://redis.io
准备
-
使用mac的包管理工具
brew
安装,若未安装brew
,可在命令行输入下面命令进行安装/bin/bash -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"
安装
-
在终端运行下面命令:
brew install redis
-
安装信息
==> Downloading https://mirrors.ustc.edu.cn/homebrew-bottles/bottles/redis-6.0.1 ######################################################################## 100.0% ==> Pouring redis-6.0.1.mojave.bottle.tar.gz ==> Caveats To have launchd start redis now and restart at login: brew services start redis Or, if you don't want/need a background service you can just run: redis-server /usr/local/etc/redis.conf ==> Summary 🍺 /usr/local/Cellar/redis/6.0.1: 13 files, 3.7MB
redis
默认安装在/usr/local/Cellar
下,配置文件redis.conf
在/usr/local/etc
下。
Redis启停
-
启动
redis
brew services start redis
-
查看
redis
启动状态brew services info redis
-
如果redis正在运行,你将看到下面信息
redis (homebrew.mxcl.redis) Running: ✔ Loaded: ✔ User: miranda PID: 67975
-
关闭
redis
brew services stop redis
配置Redis
打开配置文件
-
使用下面命令,打开目录
open /usr/local/etc
找到
redis.conf
,使用文本编辑器打开
修改配置文件
-
修改配置文件
# 指定端口 bind 0.0.0.0 # 设置守护进程,后台运行 daemonize yes # 设置密码 requirepass 123123
-
其他常见配置,可不修改
# 监听的端口 prot 6397 # 工作目录 dir . # 数据库数量 databases 16 # 设置redis能够使用的最大内存 maxmemory 512mb # 日志文件,默认为空 logfile "redis.log"
Redis常见命令
Redis数据结构介绍
Redis是一个key-value的数据库,key一般是String类型,不过value的类型多种多样
-
官方学习文档
Redis通用命令
-
KEYS:查看符合模板的所有key,不建议在生产环境设备上使用
-
DEL:删除一个指定的key
-
EXISTS:判断key是否存在
-
EXPIRE:给一个key设置有效期,有效期到期时该key会被自动删除
EXPIRE name 10 # 10s
-
TTL:查看一个KEY的剩余有效期
可以通过help [command]
可以查看一个命令的具体用法!
String类型
String类型,也就是字符串类型,是Redis中最简单的存储类型。
其value是字符串,不过根据字符串的格式不同,又可分为3类:
- string:普通字符串
- int:整数类型,可做自增、自减操作
- float:浮点类型,可做自增、自减操作
不管是哪种格式,底层都是字节数组形式存储,只不过是编码方式不同。字符串类型的最大空间不能超过512m.
KEY | VALUE |
---|---|
msg | Hello world |
num | 10 |
score | 92.5 |
String常见命令有:
-
SET:添加或者修改已存在的一个String类型的键值对
-
GET:根据key获取String类型的value
-
MSET:批量添加多个String类型的键值对
-
MGET:根据多个key获取多个String类型的value
-
INCR:让一个整型key自增1
-
INCRBY:让一个整型key自增并且指定步长,例如:
INCRBY age -1 # 自减,等同DECR
-
INCRBYFLOAT:让一个浮点类型的数字自增并指定步长
-
SETNX:添加一个String类型的键值对,前提是这个key不存在,否则不执行
-
SETEX:添加一个String类型的键值对,并且指定有效期
Redis的key允许有多个单词形成层级结构,多个单词之间用” :“隔开,格式如下:
项目名:业务名:类型:id
这个格式并非固定,也可以根据自己的需求来删除或添加词条。
例如我们的项目名称叫 heima
,有user
和product
两种不同类型的数据,我们可以这样定义key:
- user相关的key:
heima:user:1
- product相关的key:
heima:product:1
如果Value是一个Java对象,例如一个User对象,则可以将对象序列化为JSON字符串后存储
KEY | VALUE |
---|---|
heima:user:1 | |
heima:product:1 |
Hash类型
Hash类型,也叫散列,其value是一个无序字典,类似于Java中的
HashMap
结构。
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的字段自增且指定步长
HINCRBY test:hash age 2
-
HSETNX:添加一个hash类型的key的field值,前提是这个field不存在,否则不执行
List类型
Redis中的List类型与Java中的LinkedList类似,可以看做是一个双向链表结构。既可以支持正向检索和也可以支持反向检索。
特征也与LinkedList类似:
- 有序
- 元素可重复
- 插入和删除块
- 查询速度一般
常用来存储一个有序数据,例如:朋友圈点赞列表,评论列表等.
List常见的命令:
- LPUSH key [element]:向列表左侧插入一个或多个元素
- LPOP key:移除并返回列表左侧的第一个元素,没有返回null
- RPUSH key [element]:向列表右侧插入一个或多个元素
- RPOP key:移除并返回列表右侧的第一个元素
- LRANGE key star end:返回一段角标范围内的所有元素
- BLPOP和BRPOP:与LPOP和RPOP类似,只不过在没有元素时等待指定时间,而不是直接返回null
思考
如何利用List结构模拟一个栈?
- 先进后出,入口和出口在同一边
如何利用List结构模拟一个队列
- 先进先出,入口和出口在不同边
如何利用List结构模拟一个阻塞队列?
- 入口和出口在不同边
- 出队时采用BLPOP或BRPOP
Set类型
Redis的Set结构与Java中的HashSet类似,可以看做是一个value为null的HashMap。
因为也是一个hash表,因此具备与HashSet类似的特征:
- 无序
- 元素不可重复
- 查找快
- 支持交集、并集、差集等功能
Set类型常见的命令
- SADD key member:向set中添加一个或多个元素
- SREM ley 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的并集
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客户端
安装完成Redis,我们就可以操作Redis,实现数据的CRUD了。这需要用到Redis客户端,包括:
- 命令行客户端
- 图形化桌面客户端
- 变成客户端
命令行客户端
Redis安装完成后就自带了命令行客户端:redis-cli
-
使用如下命令
redis-cli [options] [commonds]
其中常见的options有:
-h 127.0.0.1
:指定要连接的redis节点的IP地址,默认是127.0.0.1
-p 6379
:指定要连接的redis节点的端口,默认是6379-a 123123
:指定redis的访问密码
-
其中的
commands
就是Redis的操作命令,例如:ping
:与redis服务端做心跳测试,服务端正常会返回pong
-
不指定,则进入
redis-cli
的交互控制台
图形化桌面客户端
- 安装完成后就可以使用了
Java客户端
在Redis官网提供了各种语言的客户端,地址:https://redis.io/clients
Java常用客户端
- Jedis
- lettuce
- SpringDataRedis
Jedis
Jedis官网地址:https://github.com/redis/jedis
快速入门
-
新建Maven工程,引入下面的依赖
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.7.0</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>RELEASE</version> <scope>compile</scope> </dependency>
-
编写测试类,与Redis建立连接
private Jedis jedis; @BeforeEach void setUp() { // 获取连接 jedis = new Jedis("127.0.0.1", 6379); // 设置密码 jedis.auth("123123"); // 选择库 jedis.select(0); }
-
操作方法
@Test void testString() { String result = jedis.set("name", "swcode"); System.out.println("result = " + result); // 获取数据 String name = jedis.get("name"); System.out.println("name = " + name); }
-
释放资源
@AfterEach void tearDown() { if (jedis != null) { jedis.close(); } }
Jedis连接池
Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此我们推荐大家使用Jedis连接池代替Jedis的直连方式
public class JedisConnectionFactory {
private static final JedisPool jedisPool;
static {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(8);
poolConfig.setMaxIdle(8);
poolConfig.setMinIdle(0);
poolConfig.setMaxWaitMillis(1000);
// 创建连接池对象
jedisPool = new JedisPool(poolConfig,"127.0.0.1", 6379, 1000, "123123");
}
public static Jedis getJedis() {
return jedisPool.getResource();
}
}
从连接池中获取jedis对象
jedis = new Jedis("127.0.0.1", 6379);
// 改为
jedis = JedisConnectionFactory.getJedis();
SpringDataRedis
SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做
SpringDataRedis
官网地址:https://spring.io/projects/spring-data-redis
- 提供了对不同Redis客户端的整合(
Lettuce
和Jedis
) - 提供了对不同RedisTemplate同一API来操作Redis
- 支持Redis的发布订阅模型
- 支持Redis哨兵和Redis集群
- 支持基于Lettuce的响应式编程
- 支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化
- 支持基于Redis的JDKCollection实现
SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中:
快速入门
SpringBoot已经提供了对SpringDataRedis的支出,使用非常简单:
-
使用Spring Initializr创建SpringBoot项目,选择以下依赖:
- Lombok
- Spring Data Redis
-
确保引入以下依赖
<!-- Redis依赖 --> <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> <!-- Lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
-
编写配置文件
spring: redis: host: 127.0.0.1 port: 6379 password: 123123 lettuce: pool: max-active: 8 max-idle: 8 min-idle: 8 max-wait: 100ms
-
编写测试类执行测试方法
@SpringBootTest class RedisDemoApplicationTests { @Autowired private RedisTemplate redisTemplate; @Test void testString() { redisTemplate.opsForValue().set("name", "Google"); Object name = redisTemplate.opsForValue().get("name"); System.out.println(name); } }
RedisSerializer配置
RedisTemplate可以接收任意Object作为值写入Redis,只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化
得到的结果是这样的:
缺点:
- 可读性差
- 内存占用较大
解决方案:
-
配置Reids
@Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) { // 1.创建RedisTemplate对象 RedisTemplate<String, Object> template = new RedisTemplate<>(); // 2.设置连接工厂 template.setConnectionFactory(connectionFactory); // 3.创建序列化对象 StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); // 4.设置key和hashKey采用String的序列化方式 template.setKeySerializer(stringRedisSerializer); template.setHashKeySerializer(stringRedisSerializer); // 5.设置value和hashValue采用json的序列化方式 template.setValueSerializer(jsonRedisSerializer); template.setHashValueSerializer(jsonRedisSerializer); return template; } }
-
此时我们已经将RedisTemplate的key设置为
String序列化
,value设置为Json序列化
的方式,再来执行方法测试 -
由于我们设置的value序列化方式是Json的,因此我们可以直接向redis中插入一个对象
@Test void testSaveUser() { redisTemplate.opsForValue().set("user:100", new User("swcode", 21)); Object name = redisTemplate.opsForValue().get("user:100"); System.out.println(name); }
尽管Json序列化可以满足我们的需求,但是依旧存在一些问题。
如上图所示,为了在反序列化时知道对象的类型,JSON序列化器会将类的class类型写入json结果中,存入Redis,会带来额外的内存开销。
那么我们如何解决这个问题呢?我们可以通过下文的StringRedisTemplate
来解决这个问题。
StringRedisTemplate
为了节省内存空间,直接使用String序列化器,只储存String类型的key和value。存储对象时,手动完成对象的序列化和反序列化
Spring默认提供了一个StringRedisTemplate类,它的key和value的序列化方式默认就是String方式。省去了我们自定义RedisTemplate的过程
-
测试StringReidsTemplate
@SpringBootTest class RedisDemoApplicationTests { @Autowired private StringRedisTemplate stringRedisTemplate; ObjectMapper objectMapper = new ObjectMapper(); @Test void testStringSaveObj() throws JsonProcessingException { User user = new User("胡歌", 21); String json = objectMapper.writeValueAsString(user); stringRedisTemplate.opsForValue().set("user:101",json); // 获取数据 String jsonUser = stringRedisTemplate.opsForValue().get("user:101"); User user1 = objectMapper.readValue(jsonUser, User.class); System.out.println("user = " + user1); } }
-
在图形客户端查看结果
总结
RedisTemplate的两种序列化实践方案,两种方案各有各的优缺点,可以根据实际情况选择使用。
方案一:
- 自定义RedisTemplate
- 修改RedisTemplate的序列化器为GenericJackson2JsonRedisSerializer
方案二:
- 使用StringRedisTemplate
- 写入Redis时,手动把对象序列化JSON
- 读取Redis时,手动把读取到的JSON反序列化为对象
下一篇文章:使用Redis实现短信登陆
本文来自博客园,作者:sw-code,转载请注明原文链接:https://www.cnblogs.com/sw-code/p/16828057.html