【建议收藏】Redis学习笔记
目录
- Redis缓存型数据库基础
- 概述
- 能干什么?
- 特性
- 学习中需要用的东西
- 安装
- 基本常识
- Redis口令
- 为什么Redis是6379?
- Redis读写方案
- Redis数据类型
- Redis-Key
- String
- List
- Set:无序不重复集合
- Hash哈希表
- Zset有序集合
- 三种特殊数据类型
- geospatial
- Hyperloglog数据结构
- Hyperloglog的优点
- Bitmaps位图
- 事务回顾
- Redis事务
- **Redis事务本质:一组命令的集合。**
- 面试常问:Redis监控(Watch)和实现乐观锁
- Jedis
- Jedis事务
- Spring集成Redis
- 整合测试
- 基础总结
- Redis进阶导论
- Redis.conf详解
- **maxmemory-policy 六种策略**
- Redis持久化
- RDB
- **rdb触发机制**
- 如何恢复rdb文件
- AOF
- 优点和缺点
- RDB和AOF的扩展
- Redis发布订阅
- Redis 发布订阅命令
- 测试
- Redis订阅发布原理
- Redis主从复制
- 主从复制的作用
- 环境配置
- 一主二从伪集群模式搭建:
- 细节
- 测试:
- 主从复制原理
- 崩星咆哮炮主从复制模型搭建(”我是火车王“模型)
- 如果此时主机崩溃,如何才能从从机中选出一个当作新主机?
- Redis主从复制哨兵模式(工作中用)
- 测试
- 哨兵模式的全部配置如下
- Redis缓存穿透和雪崩(面试高频、工作常用)
- 缓存穿透
- 缓存击穿(注意不是缓存穿透)
- 缓存雪崩
- 小结:
Redis缓存型数据库基础
概述
Redis,远程字典服务。
能干什么?
- 数据持久化:RDB、OF
- 效率高,高速缓存
- 发布订阅系统
- 地图信息分析
- 计时器、浏览量
- …
特性
- 多样的数据类型
- 持久化
- 事务
- 集群
- …
学习中需要用的东西
Redis官网:http://redis.io/
Redis中文网:http://www.redis.cn/
Github
Linux
安装
Redis版本5.0.7
gcc版本4.8
redis解压目录:/redis-5.0.7
redis配置文件目录 /usr/local/bin/wzconfig/redis.conf
基本常识
redis有13个数据库
一秒可以写81000次或者读110000次
Redis口令
Redis中存储方式是键值对(key-value),所以set key 值为录入数据,get key为取得数据
连接redis操作:cd /usr/local/bin进入redis安装目录,选择redis配置文件redis-server wzconfig/redis.conf,连接 redis-cli -p 6379
select 3,切换第4个数据库
dbsize,当前数据库大小
set name wz:意思是新增一字段name,值为wz
get name:取得字段name的值
keys *:查看所有键名
flushdb:清空当前库
flushall:清空所有库
exists name:判断内存中键值对是否存在,存在返回1,不存在返回0
MOVE name 1:移动键为name的键值对到1号数据库中
EXPIRE name 10:设置键为name的键值对10秒后自动过期
ttl name:查看键为name的键值对过期剩余时间
type name:查看键name对应值的类型
启动redis服务
[root@iZwz923i6d0otioytcumi9Z bin]# redis-server wzconfig/redis.conf # 选择启动redis的配置文件
22096:C 07 Dec 2020 16:33:36.518 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
22096:C 07 Dec 2020 16:33:36.518 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=22096, just started
22096:C 07 Dec 2020 16:33:36.518 # Configuration loaded
[root@iZwz923i6d0otioytcumi9Z bin]# redis-cli -p 6379 # 启动
为什么Redis是6379?
6379在是手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字。MERZ长期以来被antirez及其朋友当作愚蠢的代名词。Redis作者antirez同学在twitter上说将在下一篇博文中向大家解释为什么他选择6379作为默认端口号。而现在这篇博文出炉,在解释了Redis的LRU机制之后,向大家解释了采用6379作为默认端口的原因。
Redis读写方案
Redis是单线程的
Redis是很快的,Redis是基于内存操作的,所以Redis是根据机器的内存和网络带宽,而不是CPU。
Redis是C语言写的,为什么单线程还这么快?
1、误区1:高性能的服务器一定是多线程的。
2、误区2:多线程(和CPU调度有关,CPU上下文会切换)一定比单线程效率高。
速度比:CPU>内存>硬盘
核心:Redis是将所有的数据全部放在内存中的,所以使用单线程操作效率就是最高的,多线程产生的CPU上下文切换导致速度变慢。对于内存系统来说,没有上下文切换,效率就是最高的,多次读写都在一个CPU上那么单线程就是最佳方案。
Redis数据类型
Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理(消息中间件MQ)。它支持字符串、哈希表、列表、集合、有序集合,位图,hyperloglogs等数据类型。内置复制、Lua脚本、LRU收回、事务以及不同级别磁盘持久化功能,同时通过Redis Sentinel提供高可用,通过Redis Cluster提供自动分区。
Redis-Key
exists name# 判断内存中键值对是否存在,存在返回1,不存在返回0MOVE name 1# 移动键为name的键值对到1号数据库中EXPIRE name 10# 设置键为name的键值对10秒后自动过期ttl name# 查看键为name的键值对过期剩余时间type name# 查看键name对应值的类型
String
90%的Java程序员使用redis只会使用一个String类型
append key1 wz # 在key1后面追加字符串wz,如果key1是不存在的,相当于set key1 wzINCR age# 使age对应的值自增1
INCRBY age 10# 使age对应的值自增10
DECR age# 使age对应的值自减1
DECRBY age 10# 使age对应的值自减5getrange key1 0 3 #取得key1值的字符串中下标为0到3的字符getrange key1 0 -1# 取得key1值的整个字符串SETRANGE key2 2 q# 替换key2值的下标为2位置的字符SETEX key3 30 "hello" #如果key3存在,则设置其值为hello,并在30秒还过期,否则创建失败
SETNX mykey "redis" # 如果mykey不存在,则创建mykey并设置值为redis,否则创建失败。在分布式锁中经常使用mset k1 vi k2 v2 k3 v3 #同时设置多个键值对,kl对v1,k2对v2,k3对v3
mget k1 k2 k3 # 使用多个键同时取得多个值,输出结果如下
1) "vi"
2) "v2"
3) "v3"
msetnx k4 v4# 如果k4不存在,则创建k4并赋值为v4
msetnx k1 v1 k4 v4# 如果k1和k4都不存在,则创建k1和k4并赋值为v1和v4,如果有一个已经存在,则失败。原子性操作#对象
set user:1{name:zhangsan,age:3}# 设置一个user:1对象,值为json字符串来保存对象# 这里的key是一个巧妙的设计:user:{id}:{filed}mset user:1:name zhangsan user:1:age 20
# 即通过key加id加属性的方式实现工整有序不重复的存储。可以使用key:{id}:属性1、key:{id}:属性2,key:{id}:属性3等的方式拼出一个完整对象#
getset db "redis"# 相当于get db得到原值并输出后,set db "redis"。如果不存在则返回null并设置新值,如果存在先返回原值再设置新的值
String类型的使用场景:value除了是字符串还可以是数字!
- 计数器
- 浏览量
- 统计多单位的数量,例:uid:999999:follow 0,设置uid为999999的用户粉丝数为0
- 对象缓存存储
List
列表,redis中List可以实现:栈、队列、阻塞队列。
所有的list命令都是L开头的
LPUSH wzlist one #从左侧插入,将一个值或者多个值插入到列表的头部,写入顺是1,2,3存储顺序是3,2,1
LRANGE wzlist 0 -1#取得wzlist列表中所有内容
LRANGE wzlist 0 1#取得wzlist列表中下标为0到下标为1的内容(后进先出,最后进来的下标是0)
RPUSH wzlist right#从右侧插入,将一个值或者多个值插入到列表的尾部,写入顺是1,2,3存储顺序就是1,2,3
LPOP wzlist #移除名为wzlist列表的第一个元素
RPOP wzlist#移除名为wzlist列表的最后一个元素
LINDEX wzlist 0#取得wzlist列表中下标为0的值LLEN wzlist #取得wzlist列表的长度LREM wzlist 4 3# 从头部开始移除4个值为3的valueLTRIM wzlist 1 2#删除列表中除下标为1、2的其他所有元素RPOPLPUSH mylist myotherlist #移除mylist列表的最后一个元素,将其添加到myotherlist列表中LSET mylist 0 value0# 修改mylist中下标为0的值修改为value0,如果列表或者下标不存在,则报错。LINSERT mylist before "1" "haha" #将haha插入到列表中1的前面
LINSERT mylist after "2" "haha"#将haha插入到列表中2的后面
小结:实际上是一个链表,before/Node/after/left/right都可以插入值
如果key不存在,创建新的链表
如果key存在,新增内容
如果移除了所以值,只剩key,此链表为空链表,也不存在
在两边插入或者改动值,效率最高,中间元素相对来说效率低。
Set:无序不重复集合
Set中的值是不能重复的,Set指令开头都是S
127.0.0.1:6379> sadd myset hello# 向set集合myset中添加元素hello
(integer) 1
127.0.0.1:6379> SADD myset world# 向set集合myset中添加元素
(integer) 1
127.0.0.1:6379> SMEMBERS myset# 查看myset中所有的值
1) "world"
2) "hello"
127.0.0.1:6379> SISMEMBER myset hello# 查看hello是否在set中
(integer) 1
127.0.0.1:6379> SISMEMBER myset qq# 查看hello是否在set中
(integer) 0
127.0.0.1:6379> scard myset# 获取myset集合中有多少个值
(integer) 2
127.0.0.1:6379> SREM myset hello# 移除set中的值为hello的元素
(integer) 1
127.0.0.1:6379> SRANDMEMBER myset 1# 随机抽取myset集合中的1个元素
"hello"
127.0.0.1:6379> SRANDMEMBER myset 2# 随机抽取myset集合中的2个元素
"hello"
”world"##############################
127.0.0.1:6379> SMEMBERS myset
1) "hello"
2) "world"
3) "hello3"
4) "hello2"
127.0.0.1:6379> spop myset 1# 随机移除myset集合中的1个元素
"hello2"
127.0.0.1:6379> spop myset 2# 随机移除myset集合中的2个元素
"hello3"
"hello"
127.0.0.1:6379> SMEMBERS myset
1) "world"##############################
127.0.0.1:6379> SMEMBERS myset
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> SMOVE myset myset2 3# 移动myset中的为3的值到myset2中,如果myset2不存在则先创建后再移动
(integer) 1
127.0.0.1:6379> SMEMBERS myset2
1) "3"############################
# 交并差
127.0.0.1:6379> sadd key1 a
(integer) 1
127.0.0.1:6379> sadd key2 b
(integer) 1
127.0.0.1:6379> sadd key1 c
(integer) 1
127.0.0.1:6379> sadd key2 c
(integer) 1
127.0.0.1:6379> sadd key2 d
(integer) 1
127.0.0.1:6379> sadd key1 e
(integer) 1
127.0.0.1:6379> SDIFF key1 key2# 取得key1和key2的差集
1) "e"
2) "a"
127.0.0.1:6379> SINTER key1 key2# 取得key1和key2的交集
1) "c"
127.0.0.1:6379> SUNION key1 key2# 取得key1和key2的并集
1) "b"
2) "c"
3) "e"
4) "a"
5) "d"
实际应用:
微博中,A用户将所有关注的人放在一个set集合中。粉丝也放在一个set中。取得共同关注、共同好友。
六度分割理论。
Hash哈希表
Map集合,key-value集合
Hash命令以H开头
127.0.0.1:6379> hset myhash field1 wangzheng# 为myhash新增一个键值对,key:field1,value:wangzheng
(integer) 1
127.0.0.1:6379> HGET myhash field1# 查看myhash中键值对中key为field1的value值
"wangzheng"
127.0.0.1:6379> HMSET myhash field1 hello field2 world# 批量对myhash新增键值对,如果包含已存在键值对,则覆盖原有的
OK
127.0.0.1:6379> HMGET myhash field1 field2# 批量查询myhash中的field1和field2对应的value值
1) "hello"
2) "world"
127.0.0.1:6379> HGETALL myhash# 列出myhash中所有的键值对,序号奇数为key,偶数为value
1) "field1"
2) "hello"
3) "field2"
4) "world"127.0.0.1:6379> HDEL myhash field1# 删除myhash中键名为field1的键值对
(integer) 1127.0.0.1:6379> HLEN myhash# 查看myhash表长度
(integer) 3127.0.0.1:6379> HEXISTS myhash field1# 判断myhash表中是否存在field1字段
(integer) 1
127.0.0.1:6379> HKEYS myhash# 获取所有的key
1) "field2"
2) "field1"
3) "field3"27.0.0.1:6379> HINCRBY myhash field4 1# 自增1
(integer) 2127.0.0.1:6379> HSETNX myhash field hello# 如果myhash中不存在field字段则创建并赋值为hello,否则执行失败。
(integer) 0
实际应用:
和String类似,hash更适合存储对象。
用于用户信息、经常变动的信息的存储。
Zset有序集合
在set的基础上,增加了一个值score用来计数。
127.0.0.1:6379> ZADD myset 1 one# 添加一个值
(integer) 1
127.0.0.1:6379> ZADD myset 2 two 3 three# 添加多个值
(integer) 2
127.0.0.1:6379> ZRANGE myset 0 -1# 查询所有
1) "one"
2) "two"
3) "three"127.0.0.1:6379> ZADD salary 2500 xiaohong
(integer) 1
127.0.0.1:6379> ZADD salary 5000 zhangsan
(integer) 1
127.0.0.1:6379> ZADD salary 199999 wangzheng
(integer) 1
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf # 根据score从小到大排列,范围是负无穷到正无穷(从小到大不可改变)。
1) "xiaohong"
2) "zhangsan"
3) "wangzheng"
127.0.0.1:6379> ZREVRANGE salary 0 -1# 根据score从大到小排列,范围是所有元素。
1) "wangzheng"
2) "zhangsan"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 2500 withscores# 根据score从小到大排列,范围是负无穷到2500(从小到大不可改变),并显示具体值。
1) "xiaohong"
2) "2500"
127.0.0.1:6379> ZREM salary xiaohong# 移除小红
(integer) 1
127.0.0.1:6379> ZCARD salary# 获取集合中元素个数
(integer) 2
127.0.0.1:6379> ZCOUNT myset 0 1# 获取区间元素个数
(integer) 1
实际应用:
实现优先级。
排行榜
三种特殊数据类型
geospatial
地理位置
规则:两极地区无法直接添加,我实际开发中下载城市位置,使用Java一次性导入。
127.0.0.1:6379> geoadd china:city 116.4 39.9 beijing# 添加地理位置
(integer) 1
127.0.0.1:6379> GEOPOS china:city beijing# 获取指定城市的经纬度
1) 1) "116.39999896287918091" #经度2) "39.90000009167092543" #纬度
127.0.0.1:6379> GEOPOS china:city beijing shanghai aomen# 获取多个城市经纬度
1) 1) "116.39999896287918091"2) "39.90000009167092543"
2) 1) "121.40000134706497192"2) "31.20000061483705878"
3) 1) "113.49999994039535522"2) "22.19999914574732003"
127.0.0.1:6379> GEODIST china:city beijing shanghai# beijing和shanghai之间的直线距离
"1067742.3622"# 默认单位米
127.0.0.1:6379> GEODIST china:city beijing shanghai km # beijing和shanghai之间的直线距离,设置单位为千米
"1067.7424"127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km# 以经纬度110 30为原心,1000km为半径,寻找在china:city中满足这个范围内的城市。
1) "aomen"
2) "xianggang"
3) "shenzhen"
4) "guangzhou"
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km withcoord# 加一个withcoord是显示详细经纬度
1) 1) "aomen"2) 1) "113.49999994039535522"2) "22.19999914574732003"
2) 1) "xianggang"2) 1) "114.19999748468399048"2) "22.29999896492555678"
3) 1) "shenzhen"2) 1) "114.09999936819076538"2) "22.50000113800319212"
4) 1) "guangzhou"2) 1) "113.29999834299087524"2) "23.10000005307264104"
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km withdist# 加一个withdist显示直线距离
1) 1) "aomen"2) "935.1758"
2) 1) "xianggang"2) "953.3433"
3) 1) "shenzhen"2) "928.8366"
4) 1) "guangzhou"2) "834.6077"
127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 10000 km# china:city中beijing的经纬度为中心,10000千米为半径,寻找在china:city中满足这个范围内的城市
1) "aomen"
2) "xianggang"
3) "shenzhen"
4) "guangzhou"
5) "xiangshan"
6) "shanghai"
7) "beijing"
127.0.0.1:6379> GEOHASH china:city beijing shanghai# 将china:city集合中的beijing、shanghai二维的经纬度,转换成一维的字符串
1) "wx4fbxxfke0"
2) "wtw36xbc1j0"
GEO中命名的实现原理是Zset,所以我们可以使用Zset操作GEO,如下
127.0.0.1:6379> ZRANGE china:city 0 -1# 使用Zset来查询所有地理信息
1) "aomen"
2) "xianggang"
3) "shenzhen"
4) "guangzhou"
5) "xiangshan"
6) "shanghai"
7) "beijing"
127.0.0.1:6379> ZREM china:city xianggang# 删除指定地理位置
(integer) 1
127.0.0.1:6379> ZRANGE china:city 0 -1
1) "aomen"
2) "shenzhen"
3) "guangzhou"
4) "xiangshan"
5) "shanghai"
6) "beijing"
Hyperloglog数据结构
用于基数统计的算法
基数,多个数据集中不重复的元素,可以接受误差。
一个人访问同一网站多次还是算作一个人。
**传统方式:**使用set保存用户id,set不允许重复,用set的元素数量来作为判断标准。
**题:**如果保存大量用户id,导致内存占用严重。
Hyperloglog的优点
占用内存是固定的,即使存储2^64个不同元素的基数,只需要12KB内存,如果要从内存角度来比较的话,Hyperloglog是首选。
但是有0.81%的错误率。统计用户访问量(UV)数据可以忽略不计。
127.0.0.1:6379> PFADD mykey a b c d e f g h i j k l m n# 创建第一组元素
(integer) 1
127.0.0.1:6379> PFCOUNT mykey# 显示数据量
(integer) 14
127.0.0.1:6379> PFADD mykey2 o p q r s t u v w x y z# 创建第二组元素
(integer) 1
127.0.0.1:6379> PFCOUNT mykey2# 显示数据量
(integer) 12
127.0.0.1:6379> PFMERGE mykey3 mykey mykey2# 将mykey3赋值为mykey和mykey2的不重复并集,如果出现重复,则只保留一个其余的均忽略
OK
127.0.0.1:6379> PFCOUNT mykey32# 显示数据量
(integer) 25
Bitmaps位图
位存储
统计用户信息、统计疫情信息
都是操作二进制位来进行记录,就只有1和0两个状态。
如打卡每天打一次卡,365天就是365bit,1字节等于8bit,存储365天约46字节即可。
# 情景再现:员工打卡系统,sign代表打卡者,0代表星期一,1代表星期二,以此类推,记录为1代表打卡成功,记录为0代表打卡失败
# 录入
127.0.0.1:6379> setbit sign 0 1# 下标为0,记录为1,打卡
(integer) 0
127.0.0.1:6379> setbit sign 1 0# 下标为1,记录为0,未打卡
(integer) 0# 查询
127.0.0.1:6379> getbit sign 3# 查看星期四是否打卡
(integer) 0 # 否
127.0.0.1:6379> getbit sign 0# 查看星期一是否打卡
(integer) 1 # 是# 统计
127.0.0.1:6379> BITCOUNT sign# 统计sign所有数据中为1的数据的总数,即统计sign本周打卡成功的情况
(integer) 3
事务回顾
事务的四个基本特征:
Atomic(原子性):事务中包含的操作被看做一个逻辑单元,这个逻辑单元中的操作要么全部成 功,要么全部失败。Consistency(一致性):事务完成时,数据必须处于一致状态,数据的完整性约束没有被破坏,事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没 有执行过一样。
Isolation(隔离性):事务允许多个用户对同一个数据进行并发访问,而不破坏数据的正确性 和完整性。同时,并行事务的修改必须与其他并行事务的修改相互独立。
Durability(持久性):事务结束后,事务处理的结果必须能够得到固化。
Redis事务
Redis事务和普通事务的区别:
Redis单条命令保存原子性,但是事务不保证原子性。
Redis事务没有隔离性,没有隔离级别的概念。
所有的命令在事务中,并没有被直接执行,只有发起执行命令才会被执行。
Redis事务本质:一组命令的集合。
一次性:Redis中命令集合按照顺序排列在一个队列中一次执行完毕。
顺序性:一个事务中所有的命令都会被序列化,在事务执行过程中,会按照顺序执行。
排他性:事务执行中不允许其他干扰。
Redis事务步骤:
- 开启事务
- 命令入队
- 执行事务
锁:Redis实现乐观锁
127.0.0.1:6379> multi # 开启事务
OK
127.0.0.1:6379> set k1 v1# 语句入队
QUEUED
127.0.0.1:6379> set k2 v2# 语句入队
QUEUED
127.0.0.1:6379> set k3 v3# 语句入队
QUEUED
127.0.0.1:6379> exec# 执行事务// 注意在执行完exec语句后,再需要使用事务需要再次multi开启
1) OK
2) OK
3) OK127.0.0.1:6379> multi# 开启事务
OK
127.0.0.1:6379> set k1 v1# 语句入队
QUEUED
127.0.0.1:6379> set k2 v2# 语句入队
QUEUED
127.0.0.1:6379> set k4 v4# 语句入队
QUEUED
127.0.0.1:6379> DISCARD# 取消事务// 注意在执行完DISCARD语句后,再需要使用事务需要再次multi开启
OK
127.0.0.1:6379> get k4# k4存入失败,事务取消成功
(nil)# 如果语句出现问题,那么整个事务不执行。比如下面入队一个不存在的语句getset
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v3
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> getset k3
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> set k5 v5
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k3
(nil)
# 如果是语句没问题,是运行时异常,除了有问题的那一句报错且不执行以外,其他语句照常执行。比如下面让字符串类型自增
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr k1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> exec
1) (error) ERR value is not an integer or out of range
2) OK
3) "v2"
面试常问:Redis监控(Watch)和实现乐观锁
悲观锁:
- 认为所有时候都会出问题,无论做什么都加锁。
乐观锁:
- 认为所有时候都不会出现问题,所以不会上锁。
- 在更新数据的时候去判断一下,在此期间是否有人修改这个数据,使用version来判断。
- 更新时候比较和上次的version是否一致。
Redis监视测试
# 情景再现:持有100元money,使用20元out
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> WATCH money# 监视money对象,一旦事务执行成功,监控就会自己取消掉,如果事务没有执行成功,则需要使用unwatch语句手动解锁。
OK
127.0.0.1:6379> multi # 事务正常结束,数据期间没有发生变动,此时正常执行成功。
OK
127.0.0.1:6379> DECRBY money 20
QUEUED
127.0.0.1:6379> INCRBY out 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 80
2) (integer) 20
如果出现第一个线程还未进行修改money时,第二个线程抢先一步修改了money.
使用watch可以当做redis的乐观锁操作。
测试:
# 线程1打开监视,并启动事务,命令入队。
127.0.0.1:6379> watch money # 监视当前money的值
OK
127.0.0.1:6379> multi# 启动事务
OK
127.0.0.1:6379> DECRBY money 10# 命令入队
QUEUED
127.0.0.1:6379> INCRBY out 10# 命令入队
QUEUED# 线程2突然出现,修改了money的值,此时线程1的事务还没有执行,但是指令已经入队
127.0.0.1:6379> set money 1000# 修改money值
OK# 线程1,执行事务失败,返回空
127.0.0.1:6379> exec# 执行事务
(nil)# 此时想要继续完成操作,需要解开监视,加监视,启动事务,命令入队,完成执行。
127.0.0.1:6379> unwatch# 解开监视
OK
127.0.0.1:6379> watch money# 监视最新money的值
OK
127.0.0.1:6379> multi# 启动事务
OK
127.0.0.1:6379> DECRBY money 10# 命令入队
QUEUED
127.0.0.1:6379> INCRBY out 10# 命令入队
QUEUED
127.0.0.1:6379> EXEC# 比对监视的值是否发生变化,如果没有变化,执行成功。否则执行失败
1) (integer) 990
2) (integer) 30
Jedis
使用Java来操作Redis,Jedis是Redis推荐的Java连接开发工具,是Java操作Redis的中间件。
导入Jedis包:
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.2.0</version></dependency>
编码测试:
连接数据库
public class TestPing {public static void main(String[] args) {// 1、 new一个Jedis对象Jedis jedis = new Jedis("127.0.0.1",6379);// Jedis所有的命令就是Redis命令System.out.println(jedis.ping());//连接成功输出PONG} }
操作命令
结束测试
常用API
String
List
Set
Hash
Zset
略
三种特殊类型
略
Jedis事务
public class TestTX {public static void main(String[] args) {//连接Jedis jedis = new Jedis("127.0.0.1", 6379);JSONObject jsonObject = new JSONObject();jsonObject.put("hello","world");jsonObject.put("name","wz");//开启事务Transaction multi = jedis.multi();String res = jsonObject.toJSONString();
// jedis.watch(res);try {multi.set("user1",res);multi.set("user2",res);int i = 1/0;// 异常模拟multi.exec();// 执行事务}catch (Exception e){multi.discard();// 如果出现异常,就放弃事务。e.printStackTrace();}finally {System.out.println(jedis.get("user1"));System.out.println(jedis.get("user2"));jedis.flushDB();jedis.close(); //关闭连接}}
}
Spring集成Redis
SpringBoot相关的数据操作都被封装到SpringData中,如JDBC、JPA、MongoDB、Redis等等。
MyBatis是主动迎合的Spring,发布了MyBatis-Spring,所以MyBatis不在SpringData中。
SpringBoot2.x之后底层由Jedis替换为了lettuce
Jedis:采用的直连,多个线程操作是不安全的,如果想要避免不安全,就需要使用Jedis pool连接池,导致性能较低。BIO模式
lettuce:底层采用netty,实例可以在多个线程中进行共享,不存在线程不安全的情况。可以减少线程数据。NIO模式。
SpringRedis源码分析
public class RedisAutoConfiguration {public RedisAutoConfiguration() {}@Bean@ConditionalOnMissingBean(name = {"redisTemplate"}) // 如果不存在此方法,就实现此方法,意思就是可以自己手动实现来替代此方法。public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {//默认的RedisTemplate没有过多的设置,Redis对象都是需要序列化(即按照顺序存储)//两个泛型是<Object, Object>类型,我们后使用需要强制类型转换<String, Object>RedisTemplate<Object, Object> template = new RedisTemplate();template.setConnectionFactory(redisConnectionFactory);return template;}@Bean@ConditionalOnMissingBean // 由于String是redis中最常使用的类型,所以说单独提出来了一个beanpublic StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {StringRedisTemplate template = new StringRedisTemplate();template.setConnectionFactory(redisConnectionFactory);return template;}
}
整合测试
导入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置连接
spring.redis.host=127.0.0.1
spring.redis.port=6379
测试
值的序列化配置,默认的序列化方式是jdk序列化
private boolean initialized = false;
private boolean enableDefaultSerializer = true;
@Nullable
private RedisSerializer<?> defaultSerializer;
@Nullable
private ClassLoader classLoader;
@Nullable
private RedisSerializer keySerializer = null;
@Nullable
private RedisSerializer valueSerializer = null;
@Nullable
private RedisSerializer hashKeySerializer = null;
@Nullable
private RedisSerializer hashValueSerializer = null;
private RedisSerializer<String> stringSerializer = RedisSerializer.string();
@Nullable
private ScriptExecutor<K> scriptExecutor;
编写自己的RedisTemplate配置,固定模板,企业中可以直接使用。
作用是替代JDK序列化,解决控制台中输出英文或者中文是乱码的问题。
// 在企业开发中,我们80%不会使用原生的序列化操作,即原生的redis。
// 在真实的开发中,都会看到一个公司自己封装的RedisUtils或者RedisTools,自己实现的Redis操作。企业级开发大部分不使用原生的。
基础总结
在实际开发中:
读请求:
不要求强一致性的读请求,走Redis,要求强一致性的直接从MySQL读取。
写请求:
数据首先都写到MySQL数据库,之后更新Redis(先写redis再写MySQL的话,如果写入失败MySQL事务回滚,又因为Redis事务的性质特殊,会造成Redis中存在上一次操作的脏数据)。
MySQL和Redis处理不同的数据类型
- MySQL处理实时性数据,例如金融数据、交易数据。
- Redis处理实时性要求不高的数据,例如网站最热贴排行榜,好友列表等。
在并发不高的情况下,读操作优先读取redis,不存在的话就去访问MySQL,并把读到的数据写回Redis中;写操作的话,直接写MySQL,成功后再写入Redis(可以在MySQL端定义CRUD触发器,在触发CRUD操作后写数据到Redis,也可以在Redis端解析binlog,再做相应的操作)
在并发高的情况下,读操作和上面一样,写操作是异步写,写入Redis后直接返回,然后定期写入MySQL
需要频繁调用且不经常变动的数据使用redis操作get到转换为JSON返回给前端,就不再回到底层查询MySQL数据库,效率提升。
Redis进阶导论
Redis.conf详解
启动时通过配置文件启动的。
单位
# Redis configuration file example.
#
# Note that in order to read the configuration file, Redis must be
# started with the file path as first argument:
#
# ./redis-server /path/to/redis.conf# Note on units: when memory size is needed, it is possible to specify
# it in the usual form of 1k 5GB 4M and so forth:
#
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
#
# units are case insensitive so 1GB 1Gb 1gB are all the same.
大小写不敏感
配置文件unit单位对大小写不敏感。
包含
# Include one or more other config files here. This is useful if you
# have a standard template that goes to all Redis servers but also need
# to customize a few per-server settings. Include files can include
# other files, so use this wisely.
#
# Notice option "include" won't be rewritten by command "CONFIG REWRITE"
# from admin or Redis Sentinel. Since Redis always uses the last processed
# line as value of a configuration directive, you'd better put includes
# at the beginning of this file to avoid overwriting config change at runtime.
#
# If instead you are interested in using includes to override configuration
# options, it is better to use include as the last line.
#
# include /path/to/local.conf
# include /path/to/other.conf
好比学习Spring中可以把多个配置文件配置过来。
网络
bind 127.0.0.1 # 绑定的io
protected-mode yes# 保护模式
port 6379 # 端口设置
通用
daemonize yes #以守护进程的方式运行,默认是no需要手动开启为yespidfile /var/run/redis_6379.pid # 如果以守护进程方式运行,就需要指定一个pid进程文件# 日志四个级别
# Specify the server verbosity level.
# This can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)生产环境适用
# warning (only very important / critical messages are logged)
loglevel noticelogfile "" # 日志的文件名databases 16# 默认数据库的数量是16个always-show-logo yes # 是否总是显示logo
快照
持久化,在规定时间内执行了多少次操作则会持久化到文件.rdb .aof
redis是内存数据库,没有持久化数据断电即失去。
save 900 1 # 如果900秒(15分钟)内至少有1个key进行了修改,则进行持久化操作
save 300 10# 如果300秒(5分钟)内至少有10个key进行了修改,则进行持久化操作
save 60 10000# 如果60秒(1分钟)内至少有10000个key进行了修改,则进行持久化操作
# 我们之后会自己定义stop-writes-on-bgsave-error yes# 持久化如果出错是否还需要继续工作,默认开启,一般情况下开启
rdbcompression yes #是否压缩rdb文件,需要消耗一些CPU资源
rdbchecksum yes# 保存rdb文件时是否去错误校验rdb文件
dir ./ # rdb文件的保存目录
安全
设置redis密码,默认是没有密码的
127.0.0.1:6379> config get requirepass #查看密码
1) "requirepass"
2) ""
127.0.0.1:6379> config set requirepass root123# 设置密码
OK
127.0.0.1:6379> config get requirepass# 没有登录无法使用功能
(error) NOAUTH Authentication required.
127.0.0.1:6379> pings# 没有登录无法使用功能
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth root123 # 登录
OK
127.0.0.1:6379> config get requirepass# 登录后可以使用
1) "requirepass"
2) "root123"
限制
maxclients 10000 #设置能连接redis能连接客户端的最大数量
maxmemory <bytes># redis配置最大的内存容量
maxmemory-policy noeviction# 内存到达上限的处理策略
maxmemory-policy 六种策略
**1、volatile-lru:**只对设置了过期时间的key进行LRU(默认值)
2、allkeys-lru : 删除lru算法的key
**3、volatile-random:**随机删除即将过期key
**4、allkeys-random:**随机删除
5、volatile-ttl : 删除即将过期的
6、noeviction : 永不过期,返回错误
APPEND ONLY 模式 aof配置
appendonly no # 默认是不开启aof模式的,默认使用rdb方式持久化,在大部分情况下,rdb完全够用
appendfilename "appendonly.aof #持久化文件的名字# appendfsync always #每次都会修改sync,消耗性能
appendfsync everysec# 每1秒执行一次sync,可能会丢失者1秒的数据
# appendfsync no #不执行sync,这个时候操作系统自己同步数据,速度最快
具体配置在Redis持久化中进行学习。
Redis持久化
面试和工作持久化都是重点
RDB
数据存入,再次启动时读出。
什么时候使用?在主从复制中,rdb就是备用的,从机上面使用。
什么是RDB
rdb保存的文件是dump.rdb,关于如何触发创建dump.rdb都是在redis.conf配置的快照中进行配置的。
只要dump.rdb文件生成,即使关机失去内存,也能在下一次启动时成功读取到持久化的信息。
rdb触发机制
1、save的规则满足的情况下会自动触发.rdb文件的创建
2、执行了flushdb或者flushall也会生成 .rdb文件
3、退出redis,也会产生rdb文件
备份就会自动生成dump.rdb
只要dump.rdb文件生成,即使关机失去内存,也能在下一次启动时成功读取到持久化的信息。
如何恢复rdb文件
只需要将rdb文件放在redis启动目录下即可,redis启动时会自动检查dump.rdb文件恢复其中的数据到内存中。
127.0.0.1:6379> config get dir
1) "dir"
2) "/usr/local/bin" # 如果在此目录下存在dump.rdb文件,redis启动就会自动恢复dump.rdb中的内容到内存中。
几乎默认的配置已经够用了,但是我们还是要去学习。
优点:
1、适合打大规模的数据恢复。应用情景:服务器宕机后,redis启动目录中的dump.rdb文件将数据恢复到宕机前的模样。
2、对数据完整性要求不高。如果设置60秒内10000次访问才触发生成dump.rdb,那么在
AOF
几乎不使用
将所有命令都记录下来,有一个历史文件,恢复时候将此文件全部再执行一遍。
AOF保存的是appendonly.aof,也是在配置文件redis.conf中配置。
默认是不开启aof的,我们需要主动进行配置
no改为yes
重启redis就可以生效了
appendonly.aof创建成功
如果aof文件有错误,此时redis是启动不起来的,我们需要修复aof这个文件。
重写规则说明
redis会记录上一次aof文件的大小,如果aof文件大于64MB,将fork一个新的进程来将为aof文件进行重写。
aof默认的是文件的无限追加,所以这个文件只会越来越大。
优点和缺点
优点:
1、每一次修改都同步,文件的完整性比较好。
appendonly no # 默认是不开启aof模式的,默认使用rdb方式持久化,在大部分情况下,rdb完全够用
appendfilename "appendonly.aof #持久化文件的名字# appendfsync always #每次都会修改sync,消耗性能
appendfsync everysec# 每1秒执行一次sync,可能会丢失者1秒的数据
# appendfsync no #不执行sync,这个时候操作系统自己同步数据,速度最快
2、每秒同步一次,可能会丢失一秒的数据。
3、从不同步,效率最高。
缺点:
1、相对于数据文件来说,即aof文件远远大于rdb,修复速度也比rdb慢。
2、aop文件的读写效率慢,所以redis默认是rdb而不是aof
RDB和AOF的扩展
Redis发布订阅
Redis发布订阅是一种消息模式:发送者发送消息,订阅者接受消息。举例:微信、微博、关注系统。
Redis客户端可以订阅任意数量的频道。
三个角色:消息发送者、频道、消息订阅者
订阅并不是Redis特有的,只是Redis也可以实现。
下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:
当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:
Redis 发布订阅命令
下表列出了 redis 发布订阅常用命令:
channel频道,message消息
测试
订阅端:
# 订阅者对频道wz发起订阅
127.0.0.1:6379> SUBSCRIBE wz
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "wz"
3) (integer) 1
发布端:
# 发布者向频道wz发起消息
127.0.0.1:6379> PUBLISH wz "hello"
(integer) 1
订阅端得到发布端推送的信息展示
# 订阅者收到消息后实时更新
127.0.0.1:6379> SUBSCRIBE wz
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "wz"
3) (integer) 1
1) "message" # 消息
2) "wz" # 频道
3) "hello" # 消息内容
Redis订阅发布原理
实际应用:
1、实时消息系统。在注册完网页后,自动订阅网站官方这个频道,从而实现官方向用户的推送。
2、实时聊天。将信息回显即可。
订阅、关注系统。
稍微复杂的场景我们就会使用专门的消息中间件来做,例如MQ、Kafka
Redis主从复制
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master/leader),后者称为从节点(slave/follower);数据的复制是单向的,只能由主节点到从节点。默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。
- 一个master可以有多个slave(最少是一主二从)
- 一个slave只能有一个master
- 数据流向是单向的,master到slave(主节点到从节点,主节点写,从节点写。)
- 主从复制,读写分离。80%情况下都是在读。所以将写的请求放在主节点,读的请求放在从节点,减缓服务器压力。
主从复制的作用
ps:高可用一般指集群。
只要在公司中,主从复制就是必须使用的,因为在真实开发中不可能单机使用redis,因为会有性能瓶颈。
环境配置
只配置从机,不配置主机,因为每台redis服务器本身就默认是主节点。
127.0.0.1:6379> info replication #查看当前库的角色
# Replication
role:master
connected_slaves:0
master_replid:fb1c53140ad7f8cacaf39d7e39fd64b8014deeea
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
一主二从伪集群模式搭建:
复制三个配置文件,修改对应的配置信息。
1、修改端口号
2、pid名字
3、日志名
4、备份文件dump.rdb文件名
修改完毕后启动三个redis服务
启动成功验证:
配置从机:
从机1
127.0.0.1:6380> SLAVEOF 127.0.0.1 6379
OK
127.0.0.1:6380> info replication
# Replication
role:slave# 身份是从机
master_host:127.0.0.1
master_port:6379 # 主机端口号
master_link_status:up
master_last_io_seconds_ago:9
master_sync_in_progress:0
slave_repl_offset:14
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:38d163d200d5c9b7c6e88773fe8564802f0e67a6
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:14
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:14
从机2
127.0.0.1:6381> SLAVEOF 127.0.0.1 6379
OK
127.0.0.1:6381> info replication
# Replication
role:slave # 身份是从机
master_host:127.0.0.1
master_port:6379# 主机端口号
master_link_status:up
master_last_io_seconds_ago:7
master_sync_in_progress:0
slave_repl_offset:42
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:38d163d200d5c9b7c6e88773fe8564802f0e67a6
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:42
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:43
repl_backlog_histlen:0
查看主机信息:
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2 # 从机数
slave0:ip=127.0.0.1,port=6380,state=online,offset=84,lag=1# 从机1
slave1:ip=127.0.0.1,port=6381,state=online,offset=84,lag=1# 从机2
master_replid:38d163d200d5c9b7c6e88773fe8564802f0e67a6
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:84
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:84
真实的主从配置应该是在配置文件中配置,我们这里使用的是命令,是暂时的。
细节
主机可以写,从机不能写只能读。主机中所有信息和数据都会自动被从机保存。
测试:
主机断开连接:
主机断开连接,从机依旧是连接到主机的,只是没有写操作了,从机依旧可以获得主机写入过的信息,如果此时主机重新连接了,此时可以重新获取到主机写的信息。
从机断开连接:
前提是使用命令方式设置主从复制,而不是使用配置文件实现主从复制的情况下,从机断开连接后,重新连接后此从机自动变回主机,不再能获得原来是从机身份时主机中的内容,如果此时重新变回从机,就会重新获得主机的内容。
主从复制原理
- 全量复制
- 增量复制
崩星咆哮炮主从复制模型搭建(”我是火车王“模型)
主机A下挂载一个从机B,从机B下挂载从机C。
此时从机B的主机是A,从机C的主机是B,A中写入数据,B读取A成功后,C也能从B中读取到A的数据。
A——>B——>C
如果此时主机崩溃,如何才能从从机中选出一个当作新主机?
127.0.0.1:6381> SLAVEOF no one # 表明已经无主机可用,将自己作为主机。
OK
127.0.0.1:6381> INFO replication # 检查主从复制配置
# Replication
role:master # 已经变为主机
connected_slaves:0
master_replid:b5b46f59a09000b5a85bd610dc24ffa564cccc74
master_replid2:38d163d200d5c9b7c6e88773fe8564802f0e67a6
master_repl_offset:7473
second_repl_offset:7474
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:43
repl_backlog_histlen:7431
如果此时主机恢复了,就只能重新配置。
Redis主从复制哨兵模式(工作中用)
自动选取主机的模式。
测试
1、创建哨兵配置文件sentinel.conf,固定名称,不能拼错。
2、在哨兵配置文件中写入
sentinel monitor myredis 127.0.0.1 6379 1# 自定义监控名称myredis,监控目标127.0.0.1下的6379端口,1的意思是如果主机挂了就自动去已挂主机下的从机中票选一个票数最多的从机,成为新的主机。
3、启动哨兵
[root@iZwz923i6d0otioytcumi9Z bin]# redis-sentinel wzconfig/sentinel.conf # 哨兵模式启动,配置文件是sentinel.conf
23516:X 08 Dec 2020 15:13:37.984 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
23516:X 08 Dec 2020 15:13:37.984 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=23516, just started
23516:X 08 Dec 2020 15:13:37.984 # Configuration loaded_._ _.-``__ ''-._ _.-`` `. `_. ''-._ Redis 5.0.7 (00000000/0) 64 bit.-`` .-```. ```\/ _.,_ ''-._ ( ' , .-` | `, ) Running in sentinel mode|`-._`-...-` __...-.``-._|'` _.-'| Port: 26379| `-._ `._ / _.-' | PID: 23516`-._ `-._ `-./ _.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | http://redis.io `-._ `-._`-.__.-'_.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | `-._ `-._`-.__.-'_.-' _.-' `-._ `-.__.-' _.-' `-._ _.-' `-.__.-' 23516:X 08 Dec 2020 15:13:37.985 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
23516:X 08 Dec 2020 15:13:37.987 # Sentinel ID is 334f503724eb834cfbbb2498f75fc2847e6b9496
23516:X 08 Dec 2020 15:13:37.987 # +monitor master myredis 127.0.0.1 6379 quorum 1
此时断开6379主机连接,哨兵模式替换开始运作
【建议收藏】Redis学习笔记相关推荐
- StackExchange.Redis学习笔记(五) 发布和订阅
StackExchange.Redis学习笔记(五) 发布和订阅 原文:StackExchange.Redis学习笔记(五) 发布和订阅 Redis命令中的Pub/Sub Redis在 2.0之后的版 ...
- Redis学习笔记1-理论篇
目录 1,Redis 数据类型的底层结构 1.1,Redis 中的数据类型 1.2,全局哈希表 1.3,数据类型的底层结构 1.4,哈希冲突 1.5,rehash 操作 2,Redis 的 IO 模型 ...
- Redis学习笔记(实战篇)(自用)
Redis学习笔记(实战篇)(自用) 本文根据黑马程序员的课程资料与百度搜索的资料共同整理所得,仅用于学习使用,如有侵权,请联系删除 文章目录 Redis学习笔记(实战篇)(自用) 1.基于Sessi ...
- Redis(学习笔记)
Redis学习笔记 1.NoSQL数据库 1.1解决的问题 1.1.1解决CPU及内存压力 1.1.2解决IO压力 1.2NoSQL数据库概述 1.2.1什么是NoSQL数据库 1.2.2适用与不适用 ...
- Redis学习笔记①基础篇_Redis快速入门
若文章内容或图片失效,请留言反馈.部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 资料链接:https://pan.baidu.com/s/1189u6u4icQYHg_9_7ovWmA( ...
- StackExchange.Redis学习笔记(二) Redis查询 五种数据类型的应用
StackExchange.Redis学习笔记(二) Redis查询 五种数据类型的应用 原文: StackExchange.Redis学习笔记(二) Redis查询 五种数据类型的应用 Connec ...
- Redis学习笔记(一) 数据类型事务异常Jredis
Redis学习笔记(一) NoSql概述 Nosql四大分类 Redis入门 简介 Windows安装 基础使用 问题 Redis4.0之前为什么是单线程 单线程为什么这么快 Redis4.0后的多线 ...
- Redis学习笔记 - 数据类型与API(1)Key
Redis学习笔记 - 数据类型与API(1)Key Key相关命令 1. 常用命令 命令 含义 时间复杂度 keys 查找所有符合给定模式 pattern 的 key O(N), N 为数据库中 k ...
- Redis学习笔记~Redis在windows环境下的安装
Redis是一个key-value的存储系统,它最大的特点就是可以将数据序列化到文件中. redis存储在服务器的内存或者文件中,它不是session,不是cookies,它只是个更安全,更稳定,更可 ...
- redis学习笔记-持久化
redis学习笔记-持久化 前言 redis持久化有两种方式:RDB和AOF.分别对应着全量复制和增量复制.深刻理解各自的实现方式及适用场景对redis的使用和运维十分重要.下面就分别介绍. RDB持 ...
最新文章
- 使用docker部署mysql 并持久化到宿主机本地
- 1、C语言面试笔试---变量定义和声明
- 源自Google、Facebook、Netflix和Cisco的10款开源安全工具很值得回味
- CentOS7升级openssh8.0及升级后无法root登陆处理
- Python Day03
- html离线地图,离线地图三维开发-添加HTML
- Gmail priority inbox帮助你减少工作量
- [No0000151]菜鸟理解.NET Framework中的CLI,CLS,CTS,CLR,FCL,BCL
- KVASER 与 Matlab联合使用
- 案例丨长江今年1号洪水平稳通过 金仓助力三峡工程防洪保电
- 用js两张图片合并成一张图片
- 标准正态分布alpha分位点
- 蓝牙电话协议HFP(Hands-Free Profile) SCO建立/释放/在通话中Audio transfer
- 双非本硕,成功上岸大数据开发 !!!
- el-dialog内的el-table实现自适应高度
- 一款仿网易云音乐Java开源系统(附源码)
- MySQL导入数据报Got a packet bigger than‘max_allowed_packet’bytes错误的解决方法
- JAVA环境变量j配置avac命令不识别不成功注意事项详细
- Loadrunner C/S关联函数(LSP)AND(LSSS)使用-案例
- 旅游指南之十四----西藏风土人情
热门文章
- Origin:如何使用Origin绘制填充区域的误差线条
- 如何理解 Spring Boot 中的 Starters?
- 简单几步教会你如何在M1版macbook上安装iphone/ipad应用
- Java学习笔记_17 项目实战之天天酷跑(四):游戏主界面
- 为什么互联网巨头们纷纷使用Git而放弃SVN?(内含Git核心命令与原理总结)
- android中导入数据
- 导数,偏导,方向倒数,梯度
- R语言epiDisplay包alpha函数计算dataframe数据中指定数据列之间的信度分析、克朗巴哈系数、标准化系数、每剔除某一条目后系数的变化、var.labels.trunc参数指定字符串长度
- pwm控制直流电机转速流程图_Arduino:直流电机PWM调速
- python itertools 使用详解