Redis相关
- 数据库类型
关系型数据库:Oracle,MySQL,SqlServer,DB2
-
NoSql数据库:NoSQL最常见的解释是“non-relational”, “Not Only SQL”也被很多人接受。NoSQL仅仅是一
个概念,泛指非关系型的数据库,区别于关系数据库,它们不保证关系数据的ACID特性。,其具体分类如下- 键值存储:这一类数据库主要会使用到一个哈希表,这个表中有一个特定的键和一个指针指向特
定的数据。Key/value模型对于IT系统来说的优势在于简单、易部署
代表: Redis - 列存储数据库:这部分数据库通常是用来应对分布式存储的海量数据。键仍然存在,但是它们的特点是指向了多个列。这些列是由列家族来安排的。
代表: HBase - 文档型数据库:文档型数据库的灵感是来自于Lotus Notes办公软件的,而且它同第一种键值存储相类似。该类型的数据模型是版本化的文档,半结构化的文档以特定的格式存储,比如JSON。文档型数据库可 以看作是键值数据库的升级版,允许之间嵌套键值。而且文档型数据库比键值数据库的查询效率更高代表: MongoDb
- 图形数据库:图形结构的数据库同其他行列以及刚性结构的SQL数据库不同,它是使用灵活的图形模型,并且能够扩展到多个服务器上。NoSQL数据库没有标准的查询语言(SQL),因此进行数据库查询需要制定数据模型。许多NoSQL数据库都有REST式的数据接口或者查询API代表: Neo4J
- 键值存储:这一类数据库主要会使用到一个哈希表,这个表中有一个特定的键和一个指针指向特
-
非关系型数据库特点:
- 数据模型比较简单.(主要)
- 需要灵活性更强的应用系统
- 对数据库性能要求较高(主要)
- 不需要高度的数据一致性(主要)
- 对于给定key,比较容易映射复杂值的环境.
-
与关系型数据区分:
关系型数据库最典型的数据结构是表,由二维表及其之间的联系所组成的一个数据组织- 优点:
- 易于维护:都是使用表结构,格式一致;
- 使用方便:SQL语言通用,可用于复杂查询;
- 复杂操作:支持SQL,可用于一个表以及多个表之间非常复杂的查询。
- 缺点:
- 读写性能比较差,尤其是海量数据的高效率读写;
- 固定的表结构,灵活度稍欠;
- 高并发读写需求,传统关系型数据库来说,硬盘I/O是一个很大的瓶颈。
- 优点:
-
非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合,可以是文档或者键值对等。
- 优点:
- 格式灵活:存储数据的格式可以是key,value形式、文档形式、图片形式等等,文档形式、图片形式等等,使用灵活,应用场景广泛,而关系型数据库则只支持基础类型。
- 速度快:nosql可以使用硬盘或者随机存储器作为载体,而关系型数据库只能使用硬盘;
- 高扩展性;
- 成本低:nosql数据库部署简单,基本都是开源软件。
- 缺点:
- 不提供sql支持,学习和使用成本较高;
- 无事务处理;
- 数据结构相对复杂,复杂查询方面稍欠。
- 优点:
- 什么是redis?
- redis定位是缓存, 提高数据读写速度, 减轻对数据库存储与访问压力
- Redis简介:是以key-value形式存储,和传统的关系型数据库不一样.不一定遵循传统数据库的一些基本要求. (非关系型的,分布式的,开源的,水平可拓展的)
- 优点:
- 对数据高并发读写(直接是内存中进行读写的)
- 对海量数据的高效率存储和访问
- 对数据的可拓展性和高可用性.
- 单线程操作,每个操作都是原子操作,没有并发相关问题(redis 6)
- 缺点:
- redis(ACID处理非常简单)
- 无法做太复杂的关系数据库模型
- 优点:
- Redis是以key-value store存储.键可以包含:(string)字符串,哈希,(list)链表,(set)集合,(zset)有序集合.这些数据集合都指出
push/pop,add/remove及取交集和并集以及更丰富的操作.redis支持各种不同方式排序,为了保证效率,数据都是缓存在内存中.它可以从周期性的把更新的数据写入到磁盘或者把修改操作写入追加的文件中.
- Redis命令用法:类型命令 key 参数数据,type key :表示查key的类型
- String类型
1. set key value #存入键值对 2. get key #取出key对应的value 3. setex key #超时时间(表示:过了多少秒这个键值对失效) value //存入key value键值对,过了超时时间便失效了,如果对已经存在的key执行setex操作,过了规定时间,那么之前存在的键值对也会被干掉,比如之前先执行了set name zs,接着又执行setex name 5 ls 那么在5秒之内,name的值为ls,当过了5秒,name就为nil了 4. ttl key #查看该key还有多少时间过期,为-2时表示已过期 5. incr key #给key对应的value值加1,如果不是数值类型的则会报错,如set name zs,此时再操作 incr name就会报错,而set age 18 ,再操作incr age就不会报错,结果为19,并且如果key之前是不存在的,那么就会创建出对应的key,默认的value是0,做一次自增就是1了 6. decr key #和上面相反,自减,与incr同理,如果当前操作的key之前不存在,那么就会自动创建,默认value为0,操作完后结果就为-1 7. del key #删除对应的键值对 8. setnx key value #表示如果当前的key之前不存在才存入该键值对,否则不处理 9.其他不常用的 incrby key num #-> 偏移值 mset k1 v1 k2 v2 ... #-> 批量存入键值对 mget k1 k2 ... #-> 批量取出键值 append key 'value' #-> 原值后拼接新内容 setrange key index value #-> 修改键对应的值,index表示开始的索引位置
- 应用情景:
- 计数器:许多运用都会使用redis作为计数的基础工具,他可以实现快速计数、查询缓存的功能,同时数据可以异步落地到其他的数据源。如:视频播放数系统就是使用redis作为视频播放数计数的基础组件。incr viewnum 1
- 共享session:出于负载均衡的考虑,分布式服务会将用户信息的访问均衡到不同服务器上,用户刷新一次访问可能会需要重新登录,为避免这个问题可以用redis将用户session集中管理,在这种模式下只要保证redis的高可用和扩展性的,每次获取用户更新或查询登录信息都直接从redis中集中获取。
- 应用情景:
- hash类型:Hash类型是String类型的field和value的映射表.或者说是一个String集合.它特别适合存储对象,相比较而言,讲一个对象存储在Hash类型里要比存储在String类型里占用更少的内存空间,并方便存储整个对象
#1.给对象添加属性值(键值对) hset key hashkey hashvalue #举例(在开发中的场景就是向user对象中添加name属性,name对应的值为zs,age对应的值为19) hset user name zs hset user age 19 #2. 取值 hget key hashkey #举例(根据对象的属性去取值,获取user对象中的name属性值) hget user name #3.对象里面对应的key是否存在 hexists key hashkey #举例(user对象中是否存在name属性) hexists user name #4.删除对象里面对应的属性 hdel key hashkey #举例(删除user中的name属性) hdel user name #5以下为其他不常用的 hincrby key hashkey #递增值 -> 递增hashkey对应的值 hlen key #-> 获取hash对象键的数量 hkeys key #-> 获取hash对象的所有键 hvals key #-> 获取hash对象的所有值 hgetall key #-> 获取hash对象的所有数据 同样有hsetnx,其作用跟用法和setnx一样
- 应用情景:
- 哈希结构相对于字符串序列化缓存信息更加直观,并且在更新操作上更加便捷。所以常常用于用户信息等管理,
- 但是哈希类型和关系型数据库有所不同,哈希类型是稀疏的,而关系型数据库是完全结构化的,关系型数据库可以做复杂的关系查询,而redis去模拟关系型复杂查询开发困难,维护成本高
- 开发中不建议使用hash, 如果真的需要用到, 使用对象, 转换成json格式字符串
- 应用情景:
- list:Redis中的List类似Java中的queue,也可以当做List来用.List类型是一个链表结构的集合,其主要功能有push,pop,获取元素等.更详细的说,List类型是一个双端链表的结构,我们可以通过相关操作进行集合的头部或者尾部添加删除元素,list的设计非常简单精巧,即可以作为栈,又可以作为队列.满足绝大多数需求.
#1.左边开始往右添加 lpush arrs aa bb cc dd #得到结果:dd cc bb aa #2如果是往右边添加(r表示右边的意思) rpush arrs aa bb cc dd #得到结果:aa bb cc dd #3.左弹出(假设arrs中的数据为a b c d) lpop arrs #得到结果为(将a弹出,剩下b c d) #4.右弹出(假设arrs中的数据为a b c d) rpop arrs #得到结果为(将d弹出,剩下a b c) #5.打印list中的数据 lrange arrs 0 -1 #从左到右打印arrs中的数据,0表示从第0个元素开始,-1就表示打印全部,其余的数值表示从第0个到第多少个,比如3就表示从第0个到第3个 #6.获取长度(这里表示获取arrs的长度) llen arrs #7.其他应用场景 linsert key before/after refVal newVal #-> 参考值之前/后插入数据 lset key index value #-> 根据索引修改数据 lrem key count value #-> 在列表中按照个数删除数据 ltrim key start end #-> 范围截取列表 lindex key index #-> 根据索引取列表中数据
- 应用情景:1.用户收藏文章列表:xxxx_user_articles:uid [aid1, aid2, aid3.....]
- set类型:Set集合是string类型的无序集合,set是通过hashtable实现的,对集合我们可以取交集,并集,差集
#1.往集合中添加元素 sadd set1 aa bb cc ff #2.列出集合中所有元素 smembers set1 #3.删除集合中的元素 srem set1 aa #这里表示删除set1集合中的aa元素 #4.随机从集合中弹出多少个元素 spop set1 3 #这里表示随机从集合中弹出3个元素 #5.求差集 sdiff set1 set2 #这里表示的是求出set1中独有的元素,比如set1中有元素(aa bb ff gg) 而set2中有元素 (aa bb cc dd),那么执行该操作后得到的结果为ff gg ,因为aa bb 是共有的,只有ff gg 是set1独有的 #6.求交集 sinter set1 set2 #这里表示的是求set1和set2的交集(就是共同都有的元素) #7.求并集 sunion set1 set2 #这里表示求set1与set2的并集,比如set1中的元素为(a b c),set2中的元素为(e f)那么其并集就为(a b c e f) #8.返回集合中元素的个数 scard set1 #表示查询set1集合中元素的个数
- 应用情景:
- 去重;
- 抽奖:
- 准备一个抽奖池:sadd luckydraw 1 2 3 4 5 6 7 8 9 10 11 12 13
- 抽3个三等奖:spop luckydraw 3
- 抽2个二等奖:spop luckydraw 2
- 抽1个二等奖:spop luckydraw 1
- 应用情景:
- zset类型:可以排序的set类型
#1.添加元素 zadd set1 1 a #这里表示往set1集合中添加元素a,并且a元素对应的分值为1,这个分值就是用来排序的 #2.一次性添加多个元素 zadd set1 2 b 3 c 4 f #这里表示同时向set1集合中添加了分值为2的b元素,分值为3的c元素,分值为4的f元素 #3.根据分值顺序排序 zrange set1 0 -1 #这里表示set1升序全部输出,0表示开始的元素,-1表示所有的元素,如果为2则表示从第0号元素到第2号元素,其余的的以此类推 #4.反序输出 zrevrange set1 0 -1 #这里表示set1反序输出所有元素,0和-1的用法同上面的正序 #5.正序返回集合中某元素的位置 zrank set1 a #这里表示返回集合set1中按照升序的规则a所处的位置,这里a的位置就是第0位,因为它在最前面 #6.反序返回集合中某元素的位置 zrevrank set1 a #这里表示返回结婚set1按照降序规则a所处的位置,这里a就是第3号元素 #7. 返回元素个数 zcard set1 #这里表示返回集合set1元素的个数 #8. 给集合中的元素增加分值,改变分值就可以改变排名了 zincrby set1 4 b #这里表示给集合set1中的b元素的分值增加了4,那么此时升序输出的话b元素就应该在最后面了,因为此时的b元素分值为2+4=6,而f是4,所以b元素分值是最大的,从而在最后面 #9.其他不常用的 zrangebyscore key min max [withscores] #-> 按照分数范围升序输出名称 zrevrangebyscore key max min [withscores] #-> 按照分数范围降序输出名称 zrem key name #-> 删除名称和分数 zremrangebyscore key min max [withscores] #-> 根据分数范围删除元素 zremrangebyrank key start end #-> 根据排名删除元素 zcount key min max #-> 按照分数范围统计个数
- 应用情景:排行榜:有序集合经典使用场景。例如视频网站需要对用户上传的视频做排行榜,榜单维护可能是多方面:按照时间、按照播放量、按照获得的赞数等。
- String类型
- 如何选用?
- 项目操作涉及到缓存操作, 首选 redis- memcache
- 如果确定使用redis, 此时需要考虑使用哪个数据类型
- 如果要排序选用zset
- 如果数据是多个且允许重复选用list
- 如果数据是多个且不允许重复选用set
- 剩下的使用string
- 有些公司约定: 所有的redis的key跟value都使用字符串(排除使用zset场景)1>如果要排序选用zset;2>剩下的使用string
java list ---- redis JSON.toJsonString(list) java set --- redis set java set ----redis JSON.toJsonString(set)
- java操作中如果使用各种类型: list set其他的操作redis时需要明确指定的泛型, 麻烦所以有些公司统一规范, 统一使用字符串, 减少泛型操作
- 怎么设计key与value值
- 唯一性
- 可读性(就是见名知意),比如
设计keyvalue 缓存用户收藏文章列表 key value article_favor:uid1 [1,2,3,4] article_favor:uid2 [1,2,3,4]
- 灵活性
- 时效性
- value的值根据需求决定
- redis高级命令
- keys * 查询redis中所有的key
- exists key 是否存在某个key(例:exists name是否存在name的键值对)
- expire key seconds 使某个key经过多少秒后失效(例:expire name 10 //表示10秒之后key为name的这个键值对就被干掉了)
- persist key 使操作了expire操作失效,即撤销过期操作
- flushdb清空当前的数据库,flushall清空所有数据库
/*select 选择数据库 数据库为0到15(一共16个数据库) 默认进入的是0数据库 move [key] [数据库下标] 将当前数据中的key转移到其他数据库中 randomkey 随机返回数据库里的一个key rename重命名key echo 打印名 dbsize 查看数据库的key数量 info 获取数据库信息 config get 实时传储收到的请求(返回相关的配置信息) config get * 返回所有配置*/
- redis安全性:
/*因为redis速度非常快,所以在一台比较好的服务器下,一个外部用户在一秒内可以进行15w次的密 码尝试,这意味你需要设定非常强大的密码来方式暴力破解. vi编辑redis.conf文件,找到下面进行保存修改 requirepass [密码] 重启服务器 pkill redis-server 再次进入127.0.01:6379>keys * (error)NOAUTH Authentication required. 会发现没有权限进行查询auth [密码] 输入密码则成功进入 每次进入的时候都需要输入免密,还有种简单的方式: redis-cli -a [密码]*/
- redis事务
/*1.Redis的事务非常简单,使用方法如下: 首先是使用multi方法打开事务,然后进行设置,这时设置的数据会放到队列里进行保存.最后使用exec执行.把数据依次存储到redis中.使用discard方法取消事务 2.注意注意注意:redis的事务并不是原子性的,它只是把一堆任务打包放到一起执行,其中一个任务挂了,并不会影响其他任务的执行,所以是个假事务 */
- redis持久化机制:Redis是一个支持持久化的内存数据库,也就是说redis需要经常将内存中中的数据同步到硬盘来保证持久化;Redis持久化的两种方式:
- RDB方式:snapshotting(快照)默认方式.将内存中以快照的方式写入到二进制文件中.默认为dump.rdb.可以配置设置自动做快照持久化方式.我们可以配置redis在n秒内如果超过m个key就修改自动做快照.
Snapshotting设置: save 900 1 #900秒内如果超过1个Key被修改则发起快照保存 save 300 10 #300秒内如果超过10个key被修改,则发起快照保存 save 60 10000
- RDB方式,简而言之就是快照,相当于把redis数据库,也就是内存数据库,复制一份,然后粘贴到磁盘的dump.rdb文件中-->快照针对的是整个数据库,数据库里面所有的数据,当redis重新启动时,就会把dump.rdb中所有的数据加载到内存中去,其中有个致命的缺点,就是快照是有时间间隔的,在间隔空隙里操作的数据可能丢失(不会保存在dump.rdb中)
- AOF方式:append-only file (缩写aof)的方式,由于快照方式是在一定时间间隔做一次,所以可能发生reids意外down的情况就会丢失最后一次快照后的所有修改的数据.aof比快照方式有更好的持久化性,是由于在使用aof时,redis会将每一个收到的写命令都通过write函数追加到命令中,当redis重新启动时会重新执行文件中保存的写命令来在内存中重建这个数据库的内容.这个文件在bin目录下:appendonly.aof
aof默认是关闭的,如果要打开可以去redis.windows.conf配置文件里面去修改 aof不是立即写到硬盘中,可以通过配置文件修改强制写到硬盘中. aof设置: appendonly yes #启动aof持久化方式有三种修改方式 appendfsync always #收到命令就立即写到磁盘,效率最慢.但是能保证完全的持久化 appendfsync everysec #每秒写入磁盘一次,在性能和持久化方面做了很好的折中 appendfsync no #完全以依赖os 性能最好,持久化没保证
- Redis内存淘汰机制及过期Key处理:https://www.cnblogs.com/maguanyue/p/12090414.html
- RDB方式:snapshotting(快照)默认方式.将内存中以快照的方式写入到二进制文件中.默认为dump.rdb.可以配置设置自动做快照持久化方式.我们可以配置redis在n秒内如果超过m个key就修改自动做快照.
- 基本使用:
org.springframework.boot spring-boot-starter-parent 2.4.3 org.springframework.boot spring-boot-starter redis.clients jedis org.springframework.boot spring-boot-starter-test test - 集成SpringBoot
在application.poperties中做好如下配置org.springframework.boot spring-boot-starter-data-redis org.springframework.boot spring-boot-starter-test test
编写java代码#application.properties spring.redis.host=127.0.0.1 spring.redis.port=6379 #如果有密码,这里才要设置 # spring.redis.password=admin
@Autowired private StringRedisTemplate redisTemplate; @Test public void testRedisTemplate() { // 操作string redisTemplate.opsForValue().xx(); // 操作hash redisTemplate.opsForHash().xx(); // 操作list redisTemplate.opsForList().xx(); // 操作set redisTemplate.opsForSet().xx(); // 操作zset redisTemplate.opsForZSet().xx(); } ----------------------------------------- redisTemplate.opsForValue();//操作字符串 redisTemplate.opsForHash();//操作hash redisTemplate.opsForList();//操作list redisTemplate.opsForSet();//操作set redisTemplate.opsForZSet();//操作有序set
配置文件详解:
- redis之详解redis.conf配置文件_清风自来-CSDN博客
- Redis (十三) redis-4.0.8 配置文件解读 - 跃小云 - 博客园 (cnblogs.com)