黑马Redis | 基础篇
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
目录
一、SQL和NoSQL的区别
结构化与非结构化
传统的关系性数据库是结构化数据每一张表都有严格的约束信息字段名、字段数据类型、字段约束等插入的数据必须遵守这些约束
而NoSQL非关系型数据库没有严格约束形式松散自由可以是键值对存文档存图来存。
关联和非关联
关系型数据库表与表之间存在关联例如外键
非关系型数据库不存在关联要维护要考代码中的业务逻辑要么就靠数据之间的耦合
查询方式
关系型数据库可以基于sql查询语法有统一标准而非关系型数据库查询语法差异极大五花八门各种各样不过现在一些nosql也开始卷起来了一些可以用弱sql
事务
传统的关系型数据库支持事务非关系型可能支持也可能不支持或者说不能严格保证ACID的特性只能实现基本的一致性
总结
二、Redis数据类型和命令
1、通用命令
通用指令是部分数据类型的都可以使用的指令常见的有
- KEYS查看符合模板的所有key不建议在生成环境设备使用keys *查询所有的key
- DEL删除一个指定的keyDEL k1 k2 k3 k4
- EXISTS判断key是否存在
- EXPIRE给一个key设置有效期有效期到期时该key会被自动删除
- TTL查看一个KEY的剩余有效期
2、数据类型
Redis是典型的key-value数据库key一般是字符串而value包含很多不同的数据类型
3、String类型
String类型也就是字符串类型是Redis中最简单的存储类型。
其value是字符串不过根据字符串的格式不同又可以分为3类
- string普通字符串
- int整数类型可以做自增、自减操作
- float浮点类型可以做自增、自减操作
不管是哪种格式底层都是字节数组形式存储只不过是编码方式不同。字符串类型的最大空间不能超过512m.
String的常见命令
- SET添加或者修改已经存在的一个String类型的键值对
- GET根据key获取String类型的value
- MSET批量添加多个String类型的键值对
- MGET根据多个key获取多个String类型的value
- INCR让一个整型的key自增1
- INCRBY:让一个整型的key自增并指定步长例如incrby age-1 让age值自增-1
- INCRBYFLOAT让一个浮点类型的数字自增并指定步长
- SETNX添加一个String类型的键值对前提是这个key不存在否则不执行。SETNX是set和nx的组合setnx name a 和 set name a nx是一样的
- SETEX添加一个String类型的键值对并且指定有效期
Key结构
Redis没有类似MySQL中的Table的概念我们该如何区分不同类型的key呢
例如需要存储用户、商品信息到redis有一个用户id是1有一个商品id恰好也是1此时如果使用id作为key那就会冲突了该怎么办
我们可以通过给key添加前缀加以区分不过这个前缀不是随便加的有一定的规范
Redis的key允许有多个单词形成层级结构多个单词之间用':'隔开格式如下
项目名:业务名:类型:id
这个格式并非固定也可以根据自己的需求来删除或添加词条。这样以来我们就可以把不同类型的数据区分开了。从而避免了key的冲突问题。
例如我们的项目名称叫 heima有user和product两种不同类型的数据我们可以这样定义key
- user相关的keyheima:user:1
- product相关的keyheima:product:1
如果Value是一个Java对象例如一个User对象则可以将对象序列化为JSON字符串后存储
EY | VALUE |
---|---|
heima:user:1 | {"id":1, "name": "Jack", "age": 21} |
heima:product:1 | {"id":1, "name": "小米11", "price": 4999} |
4、Hash类型
Hash类型也叫散列其value是一个无序字典类似于Java中的HashMap结构。
String结构是将对象序列化为JSON字符串后存储当需要修改对象某个字段时很不方便
Hash结构可以将对象中的每个字段独立存储可以针对单个字段做CRUD
常见命令
- 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
- HINCRBY:让一个hash类型key的字段值自增并指定步长
- HSETNX添加一个hash类型的key的field值前提是这个field不存在否则不执行
5、List类型
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
6、Set类型
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并集和
应用场景共同好友
7、SortedSet类型
SortedSet是一个可排序的set集合与Java中的TreeSet有些类似但底层数据结构却差别很大。SortedSet中的每一个元素都带有一个score属性可以基于score属性对元素排序底层的实现是一个跳表SkipList加 hash表。
- 可排序
- 元素不重复
- 查询速度快
因为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即可例如
- 升序获取sorted set 中的指定元素的排名ZRANK key member
- 降序获取sorted set 中的指定元素的排名ZREVRANK key memeber
三、Redis的Java客户端
在Redis官网中提供了各种语言的客户端来帮助项目中使用redis下面是java语言的
Jedis和lettuce都有优点spring data redis直接整合了这两个
所以我们直接学spring data redis就行了不过有些企业还在用jedis所以也学下
1、Jedis
基本用法
1引入依赖
2建立连接
@BeforeEach //单元测试的注解
void setUp() {
// 1.建立连接
jedis = new Jedis("192.168.150.10", 6379);
// 2.设置密码
jedis.auth("123321");
// 3.选择库
jedis.select(0);
}
3测试
@Test
void testString() {
// 存入数据
String result = jedis.set("name", "虎哥");
System.out.println("result = " + result);
// 获取数据
String name = jedis.get("name");
System.out.println("name = " + name);
}
@Test
void testHash() {
// 插入hash数据
jedis.hset("user:1", "name", "Jack");
jedis.hset("user:1", "age", "21");
// 获取
Map<String, String> map = jedis.hgetAll("user:1");
System.out.println(map);
}
4释放资源
@AfterEach
void tearDown() {
if (jedis != null) {
jedis.close();
}
}
Jedis连接池
Jedis本身是线程不安全的并且频繁的创建和销毁连接会有性能损耗因此我们推荐大家使用Jedis连接池代替Jedis的直接连接
修改完之后我们建立连接就要这样建立
2、SpringDataRedis重点
快速了解
SpringData是Spring中操作数据的模块包括各种数据库的继承
其中对Redis的继承模块就是SpringDataRedis整合了Lettuce和Jedis
而且提供了RedisTemplate统一API来操作Redis
Jedis的每个操作都变成一个方法一个对象有很多方法就很臃肿而我们redisTemplate就分开了先获取对象然后再用对象来操作。
快速入门
1引依赖common-pool2要引入因为他底层需要连接池
2配置文件只需要配置连接池就行了不用像上面自己写
3利用spring注入RedisTemplate
4直接用
序列化和反序列化
RedisTemplate是帮我们做序列化和反序列化
底层默认用的是jdk的序列化器进行序列化jdk序列化器底层用的是ObjectOutputStream这个流的作用就是把java对象转化为字节然后写入redis
所以我们正常的对象用RedisTemplate写入redis以后是字节进行存储的如下图
这样可读性差他把key和value都序列化进去了而且内存占用大很长
所以我们得把序列化器改了如果是String可以用
如果value是json对象的话可以用
我们可以配置个config来改掉默认的jdk序列化器
我们可以测试一下
取出的时候反序列化又是怎么做到的
为了这个自动反序列化json序列化器要多加一个@class来标记这样太浪费内存空间了我们必须节省空间的话怎么做到呢
所以我们并不会采取json的序列化器来处理value而是统一使用string序列化器要求只能存储string类型的key和value。当我们要存java对象的时候手动完成对象的序列化和反序列化
String默认提供了一个StringRedisTemplate类他的key和value的序列化默认就是String方式省去了定义redisTemplate过程
这样存进redis的就是一个占空间很小的对象了