门户网站做pos机,镇江网站建设网站制作公司,小程序商家入驻平台,做网站注册几类商标文章目录 1. 概况1.1 认识 NoSQL1.1.1 查询方式1.1.2 事务1.1.3 总结 2. 认识 Redis4. Redis 常见命令4.1 Redis 数据结构介绍4.2 Redis 通用命令4.3 Redis 命令之 String 命令4.4 Redis 命令的层级结构4.5 Redis 命令之 Hash 命令4.6 Redis 命令之 List 命令4.7 set 唯一不排序… 文章目录 1. 概况1.1 认识 NoSQL1.1.1 查询方式1.1.2 事务1.1.3 总结 2. 认识 Redis4. Redis 常见命令4.1 Redis 数据结构介绍4.2 Redis 通用命令4.3 Redis 命令之 String 命令4.4 Redis 命令的层级结构4.5 Redis 命令之 Hash 命令4.6 Redis 命令之 List 命令4.7 set 唯一不排序4.8 SortedSet 唯一且排序4.9 BitMap 1. 概况 1.1 认识 NoSQL
NoSql 可以翻译做Not Only Sql不仅仅是SQL或者是No Sql非Sql的数据库。是相对于传统关系型数据库而言有很大差异的一种特殊的数据库因此也称之为非关系型数据库。
1.1.1 查询方式
传统关系型数据库会基于Sql语句做查询语法有统一标准而不同的非关系数据库查询语法差异极大五花八门各种各样。
1.1.2 事务
传统关系型数据库 能满足事务ACID的原则。而 非关系型数据库 往往不支持事务或者不能严格保证ACID的特性只能实现基本的一致性。
1.1.3 总结
除了上述四点以外在存储方式.扩展性.查询性能上关系型与非关系型也都有着显著差异总结如下 2. 认识 Redis
Redis诞生于2009年全称是Remote Dictionary Server 远程词典服务器是一个基于内存的键值型NoSQL数据库。特征
键值key-value型value支持多种不同数据结构功能丰富单线程每个命令具备原子性低延迟速度快基于内存.IO多路复用.良好的编码。支持数据持久化支持主从集群.分片集群支持多语言客户端
Redis的官方网站地址https://redis.io/ 4. Redis 常见命令 4.1 Redis 数据结构介绍
Redis是一个key-value的数据库key一般是String类型不过value的类型多种多样 4.2 Redis 通用命令
通用指令是部分数据类型的都可以使用的指令常见的有
KEYS查看符合模板的所有keyDEL删除一个指定的keyEXISTS判断key是否存在EXPIRE给一个key设置有效期有效期到期时该key会被自动删除TTL查看一个KEY的剩余有效期
对应 RedisTemplate 方法
// 匹配key
redisTemplate.keys();// 判断key是否存在
redisTemplate.hasKey(key);
// 删除key
redisTemplate.delete(key);
// 指定key有效期
redisTemplate.expire(key,time,TimeUnit.MINUTES);
// 根据key获取过期时间
Long expire redisTemplate.getExpire(key);4.3 Redis 命令之 String 命令
String 类型也就是字符串类型是Redis中最简单的存储类型。其value是字符串不过根据字符串的格式不同又可以分为3类
string普通字符串int整数类型可以做自增.自减操作float浮点类型可以做自增.自减操作
不管是哪种格式底层都是字节数组形式存储只不过是编码方式不同。字符串类型的最大空间不能超过 512 MB。
String的常见命令有
SET添加或者修改已经存在的一个 String 类型的键值对GET根据 key 获取 String 类型的 valueMSET批量添加多个String类型的键值对MGET根据多个 key 获取多个 String 类型的 valueINCR让一个整型的key自增1INCRBY:让一个整型的 key 自增并指定步长例如incrby num 2 让num值自增2INCRBYFLOAT让一个浮点类型的数字自增并指定步长SETNX添加一个 String 类型的键值对前提是这个 key 不存在否则不执行SETEX添加一个 String 类型的键值对并且指定有效期
RedisTemplate 方法
ValueOperations ops redisTemplate.opsForValue();// 单独设置有效期不推荐单独用
ops.expire(StringKey,1,TimeUnit.MINUTES);// 设置值 and 有效期推荐这种
ops.set(key, value, 1, TimeUnit.MINUTES);// 操作数值 增加 减少INCR INCRBY
ops.increment(key, 1);
ops.increment(key, -1);// SETNX SETEX这个key不存在执行 存在则不执行多用于互斥锁
ops.setIfAbsent(key, value, 10, TimeUnit.SECONDS)// 获取缓存值
ops.get(StringKey); 4.4 Redis 命令的层级结构
Redis 没有类似 MySQL中的 Table 的概念我们该如何区分不同类型的key呢例如需要存储用户.商品信息到 redis有一个用户id是1有一个商品id恰好也是1此时如果使用id作为key那就会冲突了该怎么办我们可以通过给key添加前缀加以区分不过这个前缀不是随便加的有一定的规范Redis的key允许有多个单词形成层级结构多个单词之间用’:隔开格式如下项目名:业务名:类型:id这个格式并非固定也可以根据自己的需求来删除或添加词条。例如我们的项目名称叫 snow有user和product两种不同类型的数据我们可以这样定义key
user 相关的keysnow:user:1product 相关的keysnow:product:1
如果Value是一个Java对象例如一个User对象则可以将对象序列化为JSON字符串后存储
keyvaluesnow:user:1{“id”:1, “name”: “Snow”, “age”: 21}snow:product:1{“id”:1, “name”: “Apple”, “price”: 9999} 4.5 Redis 命令之 Hash 命令
Hash类型也叫散列其value是一个无序字典类似于Java中的HashMap结构。String结构是将对象序列化为JSON字符串后存储当需要修改对象某个字段时很不方便
keyvaluesnow:user:1{“id”:1, “name”: “Snow”, “age”: 88}snow:product:1{“id”:1, “name”: “Apple”, “price”: 9999}
Hash结构可以将对象中的每个字段独立存储可以针对单个字段做CRUD
Keyvaluefieldvaluesnow:user:1nameSnowage88snow:product:1nameAppleprice9999
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和valueHKEYS获取一个hash类型的key中的所有的fieldHVALS获取一个hash类型的key中的所有的valueHINCRBY:让一个hash类型key的字段值自增并指定步长HSETNX添加一个hash类型的key的field值前提是这个field不存在否则不执行
// 添加 put / putAll
// 初始数据:
template.opsForHash().put(redisHash,name,tom);
template.opsForHash().put(redisHash,age,26);
template.opsForHash().put(redisHash,class,6);MapString,Object testMap new HashMap();
testMap.put(name,jack);
testMap.put(age,27);
testMap.put(class,1);
template.opsForHash().putAll(redisHash1,testMap);// 仅当hashKey不存在时才设置散列hashKey的值。
System.out.println(template.opsForHash().putIfAbsent(redisHash,age,30));
System.out.println(template.opsForHash().putIfAbsent(redisHash,kkk,kkk));
//结果
false
true// 删除
template.opsForHash().delete(redisHash,name)// 判断key是否存在
template.opsForHash().hasKey(redisHash,age)// 获取
template.opsForHash().get(redisHash,age)// 增加散列hashKey的值整型
System.out.println(template.opsForHash().get(redisHash,age));
System.out.println(template.opsForHash().increment(redisHash,age,1));
// 结果
26
27// 获取key所对应的散列表的key
System.out.println(template.opsForHash().keys(redisHash1));
//redisHash1所对应的散列表为{class1, namejack, age27}
//结果[name, class, age]// 获取key所对应的散列表的大小个数
template.opsForHash().size(redisHash1);
//redisHash1所对应的散列表为{class1, namejack, age27}
//结果3// 获取整个哈希存储的值
template.opsForHash().values(redisHash);
// 结果[tom, 26, 6]// 获取整个哈希存储
template.opsForHash().entries(redisHash);
// 结果{age26, class6, nametom}// 使用Cursor在key的hash中迭代相当于迭代器。
CursorMap.EntryObject, Object curosr ops.scan(redisHash, ScanOptions.ScanOptions.NONE);while(curosr.hasNext()){Map.EntryObject, Object entry curosr.next();System.out.println(entry.getKey():entry.getValue());}
//结果
age:28.1
class:6
kkk:kkk4.6 Redis 命令之 List 命令
Redis中的List类型与Java中的 LinkedList 类似可以看做是一个 双向链表 结构。既可以支持正向检索也可以支持反向检索。特征也与LinkedList类似
有序元素可以重复插入和删除快查询速度一般
常用来存储一个有序数据例如朋友圈点赞列表评论列表等。
List的常见命令有
LPUSH key element … 向列表左侧插入一个或多个元素LPOP key移除并返回列表左侧的第一个元素没有则返回nilRPUSH key element … 向列表右侧插入一个或多个元素RPOP key移除并返回列表右侧的第一个元素LRANGE key star end返回一段角标范围内的所有元素BLPOP和BRPOP与LPOP和RPOP类似只不过在没有元素时等待指定时间而不是直接返回nil // 从左边插入
template.opsForList().leftPush(list,java);// 从右边插入
template.opsForList().rightPush(listRight,java);// 把一个数组批量插入到列表中
String[] stringarrays new String[]{1,2,3};
// 可以插入数组也可以插入集合
template.opsForList().leftPushAll(listarray, stringarrays);
//template.opsForList().rightPushAll(listarrayright,stringarrays);
template.opsForList().range(listarray,0, -1);
// 结果:[3, 2, 1]// 获取
template.opsForList().range(listRight,0, -1);
template.opsForList().index(listRight,2);//下标从0开始
// 结果如下:
[java, python, c]
c// 获取长度
template.opsForList().size(list)// 弹出
template.opsForList().range(list,0,-1);
template.opsForList().leftPop(list);
template.opsForList().range(list,0,-1);
// 结果:
[c, python, oc, java, c#, c#]
c
[python, oc, java, c#, c#]4.7 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的交集
eg:求交集SINTER s1 s2
求s1与s2的不同SDIFF s1 s2 A
求s1与s2的并集SUNION s1 s2
练习
将下列数据用Redis的Set集合来存储
张三的好友有李四、王五、赵六 SADD zs lisi wangwu zhaoliu 李四的好友有王五、麻子、二狗 SADD lisi wangwu mazi ergou
利用Set的命令实现下列功能
计算张三的好友有几人 SCARD zs 计算张三和李四有哪些共同好友 SINTER zs li 查询哪些人是张三的好友却不是李四的好友 SDIFF zs lisi 查询张三和李四的好友总共有哪些人 SUNION zs lisi 判断李四是否是张三的好友 SISMEMBER zs lisi 判断张三是否是李四的好友 SISMEMBER lisi zs 将李四从张三的好友列表中移除 SREM zs lisi
常用方法
// 判断当前登录用户是否已经点赞
String key BLOG_LIKED_KEY id;
Boolean isMember stringRedisTemplate.opsForSet().isMember(key, userId.toString());
// 保存用户到Redis的set集合
stringRedisTemplate.opsForSet().add(key, userId.toString());
// 把用户从Redis的set集合移除
stringRedisTemplate.opsForSet().remove(key, userId.toString());// 求两个 key 的交集
SetString intersect stringRedisTemplate.opsForSet().intersect(key, key2);使用场景 需求利用Redis中恰当的数据结构实现共同关注功能。在博主个人页面展示出当前用户与博主的共同关注呢。 当然是使用我们之前学习过的set集合咯在set集合中有交集并集补集的api我们可以把两人的关注的人分别放入到一个set集合中然后再通过api去查看这两个set集合中的交集数据。 4.8 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即可例如
升序获取sorted set 中的指定元素的排名ZRANK key member降序获取sorted set 中的指定元素的排名ZREVRANK key memeber
练习题将班级的下列学生得分存入Redis的SortedSet中Jack 85, Lucy 89, Rose 82, Tom 95, Jerry 78, Amy 92, Miles 76并实现下列功能
删除Tom同学获取Amy同学的分数获取Rose同学的排名查询80分以下有几个学生给Amy同学加2分查出成绩前3名的同学查出成绩80分以下的所有同学 // 保存用户到Redis的set集合 zadd key value score
stringRedisTemplate.opsForZSet().add(key, userId.toString(), System.currentTimeMillis());// 获取当前登录用户是否已经点赞
String key BLOG_LIKED_KEY id;
Double score stringRedisTemplate.opsForZSet().score(key, userId.toString());// 把用户从Redis的set集合移除 key value
stringRedisTemplate.opsForZSet().remove(key, userId.toString());// 查询top5的点赞用户 zrange key 0 4 (范围查询)
SetString top5 stringRedisTemplate.opsForZSet().range(key, 0, 4);4.9 BitMap
BitMap 的操作命令有
SETBIT向指定位置offset存入一个0或1GETBIT 获取指定位置offset的bit值BITCOUNT 统计BitMap中值为1的bit位的数量BITFIELD 操作查询、修改、自增BitMap中bit数组中的指定位置offset的值BITFIELD_RO 获取BitMap中bit数组并以十进制形式返回BITOP 将多个BitMap的结果做位运算与 、或、异或BITPOS 查找bit数组中指定范围内第一个0或1出现的位置
实现签到
//写入Redis SETBIT key offset 1签到
stringRedisTemplate.opsForValue().setBit(key, dayOfMonth, true);统计连续签到天数
Override
public Result signCount() {// 1.获取当前登录用户Long userId UserHolder.getUser().getId();// 2.获取日期LocalDateTime now LocalDateTime.now();// 3.拼接keyString keySuffix now.format(DateTimeFormatter.ofPattern(:yyyyMM));String key USER_SIGN_KEY userId keySuffix;// 4.获取今天是本月的第几天int dayOfMonth now.getDayOfMonth();// 5.获取本月截止今天为止的所有的签到记录返回的是一个十进制的数字 BITFIELD sign:5:202203 GET u14 0ListLong result stringRedisTemplate.opsForValue().bitField(key,BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));if (result null || result.isEmpty()) {// 没有任何签到结果return Result.ok(0);}Long num result.get(0);if (num null || num 0) {return Result.ok(0);}// 6.循环遍历int count 0;while (true) {// 6.1.让这个数字与1做与运算得到数字的最后一个bit位 // 判断这个bit位是否为0if ((num 1) 0) {// 如果为0说明未签到结束break;}else {// 如果不为0说明已签到计数器1count;}// 把数字右移一位抛弃最后一个bit位继续下一个bit位num 1;}return Result.ok(count);
}