目录
NoSQL数据库简介:
NoSQL解决性能的问题而产生的技术,Redis是典型的NoSQL数据库
NoSQL=not noly sql(不仅仅的sql),泛指非关系型数据库
NoSQL优点:
- 远超与SQL性能
- NoSQL直接通过内存读取
- NoSQL直接作为缓存使用
常见NoSQL数据库:Redis,MongoDB
适用场景:
- 对数据高并发的读写
- 海量数据的读写
- 对数据高可拓展性的
Redis概述及安装
开源的key-value存储系统,支持存储的value类型更多(string,list链表,set集合,zset有序集合,hash),数据既可以存到内存中,也可以周期性写入磁盘,可实现主从操作。
Redis安装:(一般都只在linux中进行安装)
下载官网:https://redis.io
Redis-cli:redis服务器启动命令 Redis-cli:客户端,操作入口 |
启动服务器:(两种方式)
进入客户端: redis-cli
停止服务:在客户端输入shutdown关闭,再输入exit退出。
方式一: 直接在bin目录下输入启动:redis-server
缺点:页面不能退出
方式二: 后台启动
Cp redis.conf /etc/redis.conf
Redis-server /etc/redis.conf(复制文件的地址) |
Redis基础学习:
Redis默认6379端口号
Redis默认16个数据库,从0开始,初始默认使用0号库
底层原理: 单线程+多路io复用
Redis键(key)命令操作如下:
Keys * 查看当前库所有的key Exists key 判断某个key是否存在 Type key 查看key是什么类型 Del key 删除指定的key数据 Unlink key 根据value选择非阻塞删除 Expire key 10 为给定的key设置过期时间 Ttl key 查看还有多少秒过期,-1表示永不过期,-2表示已过期 Select 库 切换数据库 Dbsize 查看当前数据库的key数量 Flushdb 清空当前库 Flushall 通杀全部库 |
Redis中value五大数据类型:
字符串String,列表List,集合Set,哈希Hash,有序集合Zset
一: String 字符串
String是redis中最基本的数据类型
string是二进制安全的,意思是redis中String可以包含任何数据类型。
一个redis中字符串value最多可以是512M
常用命令:
添加键值对: Set key value 查询对应键值:get key 将给定的value追加到原值的末尾:append key value 获取值的长度: strlen key 在key不存在时,设置key的值: setnx key value 为key设置过期时间:Setex key 过期时间 Incr key 将key中存的值增加1(只能对数字值操作,如果为空,新增值为1) Decr key 将key中储存的数字值减1(智能对数字值操作) Mset key1 value1 key2 value2 同时设置一个或多个key-value值 Mget key1 key2 同时获取一个或多个value Msetnx key1 value1 key2 value2 同时设置一个或者多个key-value,仅当所有给定key都不存在时 |
二: 列表List
单键多值
Redis列表是简单的字符串列表,按照插入顺序排序,底层是个双向链表
常用命令:
从左边或者右边插入多个值:lpush(左)/rpush(右) key value1 value2 value3 从左边或者右边吐出一个值:lpop(左)/rpop(右) key 按照索引下标获得元素(从左到右):lrange key 开始位置 结束位置 注意: -1表示右边第一个,0表示左边第一个。lrange key 0 -1 表示获取所有值。 从key1右边取一个值插入到key2左边: rpoplpush key1 key2 在value前或后插入一个值:linsert key before/after value value1 将列表key下标为index的值替换为value:lset key index value |
三: 集合set
和list一样类似一个列表的功能,特殊在于set是可以自动排重的
当需要存储一个列表数据,又不希望出现重复数据时,set是很好的选择
Redis中的set是string类型的无序集合,底层是value为null的hash表,在做添加,删除,查找是时间复杂度都是o(1)
常用命令:
将一个或多个value值加入到集合key中(已经存在的将被忽略): sadd key value1 value2 value3 取出该集合所有值:smembers key 判断集合key中是否有value值(1是有,0是没有): Sismember key 返回集合中元素个数:scard key 删除集合中某元素: srem key 随机吐出一个值: spop key 随机取出n个值,不会从集合中删除: Srandmember key 返回两个集合的交集元素: sinter key1 key2 返回两个元素的并集元素: sunion key1 key2 |
四: hash哈希
Redis中hash是一个string类型的field和value的映射表
很适合存储对象
常用命令:
给key哈希集合中的field赋值value: hset key field value 从key哈希集合中field取出value: hget key field 批量设置hash的值: hmset key field1 value1 field2 value2 查看哈希表key中,给定域是否存在:hexists key field 列出hash集合中所有field:hkeys key 列出该hash集合的所有value: hvals key 将哈希表key中的field值设置为value,当且仅当field不存在: hsetnx key field value |
五: 有序集合Zset
Redis中的有序集合Zset与集合set相似,是一个没有重复元素的字符串集合
不同:有序集合的每个成员关联了一个评分score,用于按从低到高排序集合中的成员。
集合成员是唯一的,评分key重复。
常用命令:
将一个或多个元素及其score值加入到有序集合key中: Zadd key score1 value score2 value2 返回有序集key中,下标在start和stop间的元素: Zrange key start stop 返回有序集key中,所有score值介于min和max间成员,按score值从小到大排序: zrangebyscore key min max 返回有序集key中,所有score值介于min和max间成员,按score值从大到小排序: zrevrangebyscore key min max 为元素的score加上增量:zincrby key increment value 删除该集合下,指定值元素:zrem key value 统计该集合,分数区间内的元素个数:zcount key min max 返回值在集合中排名,从0开始:zrank key value |
Redis配置文件信息部分详解:
Redis的发布与订阅:
Redis发送者:发送消息
Redis订阅者:接收消息
Redis客户端可以订阅任意数量的频道
操作:
打开一个客户端订阅频道channel1: Subscribe channel1 打开另一个客户端向channel1发送消息:(返回值是订阅的数量) Publish channel1 hello |
Redis新数据类型:
- Bitmaps
- HyperLogLog
- Geospatial
Bitmaps:位操作
实现对位的操作,本身不是数据类型
实际就是字符串,但可实现对字符串的位操作
常用命令:
设置bitmaps中值:Setbit key 偏移量 value(value值为0或者1) 获取bitmaps中某个偏移量的值:getbit key 偏移量 统计比特值value为1的数量:bitcount key【start end】 |
HyperLogLog:基数统计
做基数统计的算法,基数就是不重复元素
常用命令:
添加一个或多个指定元素到HyperLogLog中:pfadd key 值1 值2 计算基数数量:pfcounf key |
Geospatial:地理信息
Redis提供了经纬度设置
常用命令:
添加地理位置(经度,维度,名称):geoadd key 经度 维度 位置名称 获取指定地区坐标值:geopos key 位置名称 获取两地位置距离:geodist key 位置名称1 位置名称2 km |
Redisk客户端工具Jedis操作redis
操作:
创建maven工程,导入依赖:
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.6.2</version> </dependency> |
连接redis:
连接出现问题,解决:
- 一定要查看配置文件redis.conf(两处,解压目录下和配置后台启动放的目录下),注释bind支持远程连接,保护模式改为no
- 关闭linux防火墙
Jedis实例:收集验证码
输入手机号,点击发送,随机生成验证码,2分钟有效 输入验证码,点击验证,返回成功或失败 每个收集每天智能输入三次 |
实现:
通过类Random生成随机验证码。
把验证码放在redis中,设置过期时间为120秒。
从验证码中获取验证码和输入的验证码进行比较
然后incr每次发送之后+1,大于2的时候,提交不能发送。
代码如下:
package com.ao.jedis; import javafx.scene.shape.TriangleMesh; import redis.clients.jedis.Jedis; import java.util.Random; /** * @author Amos * @create 2021-08-2021/8/5-13:07 */ public class PhoneCode { public static void main(String[] args) { //模拟验证码发送 verifyCode("15185298117"); //getRedisCode("15185298117","498779"); } //方法一:生成六位数字验证码 public static String getcode(){ Random random = new Random(); String code = ""; for (int i=0;i<6;i++){ int rand = random.nextInt(10); code += rand; } return code; } //方法二: 每个手机每天只能发送三次,验证码放redis中,设置过期时间 public static void verifyCode(String phone){ //连接redis Jedis jedis = new Jedis("192.168.217.129",6379); //拼接key //手机发送次数key String countKey = "VerifyCode" + phone + ":count"; //验证码key String codeKey = "VerifyCode" + phone + ":code"; //每个手机每天只能发送三次 String count = jedis.get(countKey); if (count == null){ //没有发送次数,第一次发送 //设置发送次数是1 jedis.setex(countKey,24*60*60,"1"); }else if (Integer.parseInt(count)<=2){ //发送次数+1 jedis.incr(countKey); }else if (Integer.parseInt(count)>2){ System.out.println("今天发送次数已用完!"); jedis.close(); } //发送验证码放到redis中 String vcode = getcode(); jedis.setex(codeKey,120,vcode); jedis.close(); } //方法三:验证码校验 public static void getRedisCode(String phone,String code){ Jedis jedis = new Jedis("192.168.217.129",6379); String codeKey = "VerifyCode" + phone + ":code"; String s = jedis.get(codeKey); //判断 if (s.equals(code)){ System.out.println("验证成功"); }else{ System.out.println("验证失败!"); } jedis.close(); } } |
Redis事务操作:
Redis事务的主要作用就是串联多个命令防止别的命令插队
三个命令:
Multi :输入multi命令后,输入的命令会依次进入命令队列,但不会执行
Exec :输入Exec后,将之前的命令队列中的命令依次进行
Discard :通过discard放弃组队
事务冲突问题解决:
悲观锁: 就是很悲观,每次拿数据都认为别人会修改,所以每次都会上锁。
每次操作都上锁,别人不能操作,等操作完释放锁后别人才能进行操作
- 传统关系型数据就会用到,都是在操作前上锁。
乐观锁: 就很乐观,拿数据时认为别人不会修改,所以不会上锁。
在更新的时候会判断在此期间别人有没有去更新这个数据,使用版本号机制。
- 乐观锁适应多读的类型,可提高吞吐量,redis就是用乐观锁实现事务
乐观锁在redis中的使用和事务特性:
监视一个或者多个key: Watch key1【key2】
取消对命令key监视: unwatch key
Redis事务三特性:
- 单独的隔离操作: 事务执行过程中,不会被其他客户端发送的命令请求打断
- 没有隔离级别的概念:队列中命令没提交前都不会执行
- 不保证原子性:一条命令执行失败,其后命令依久执行,没有回滚