Redis笔记

为什么用Nosql

1.单机SQL的时代

网站的瓶颈:

  1. 数据量太大,一个机器放不下。
  2. 数据的索引(B + Tree),一个机器内存放不下。
  3. 访问量(读写混合),一个服务器承受不了。

如果出现以上情况,需要升级。

2.Memcached(缓存)+ MySQL + 垂直拆分 

网站80%的情况都是在读,每次都要去查询数据库的话就会十分麻烦!如果希望减轻数据的压力,可以使用缓存来保证效率。

发展过程:优化数据结构与索引—>文件缓存(IO)—> Memcached(当时最热门的的技术)

在这里插入图片描述

数据访问层(Data Access Layer)

3.分库分表 + 水平拆分 + Mysql集群

技术和业务在发展的同时,门槛会逐渐提高。
本质:数据库(读、写)

早些年MyISAM:表锁,十分影响效率!高并发下会出现严重锁问题。

后期Innodb:行锁

逐渐使用分库分表来解决写的压力。MySQL当时推出了表分区,并没有得到大范围使用。
MySQL的集群很好地满足了当时的需求。

在这里插入图片描述

4.当今时代

技术爆炸

图型数据库 JSON

MySQL存储博客、图片等较大的文件时。数据库表就会很大,效率就降低了。需要有一种新型数据库来专门处理这些数据。

基本互联网项目

在这里插入图片描述

为什么用NoSQL

用户的个人信息、社交网络、地理位置。用户自己产生的数据,用户日志等等爆发式增长!
NoSQL可以很好地处理以上问题。

NoSQL不仅仅是SQL(Not only SQL)

Map<String,Object> 使用键值对来控制。

NoSQL特点

解耦

  1. 方便扩展(数据之间没有关系,方便扩展)
  2. 大数据量高性能(Redis一秒写8万次,读取11万次,NoSQL的缓存记录级,是一种细粒度的缓存,性能比较高。)
  3. 数据类型是多样型的(不需要实现设计数据库!随取随用)

NoSQL
  • 不仅仅是数据
  • 没有固定的额查询语言
  • 键值对存储,列存储,文档存储,图像数据库(社交关系)
  • 最终一致性
  • CAP定理和BASE(异地多活)
  • 高性能、高可用、高扩展

NoSQL的四大分类

KV键值对

  • 新浪:redis
  • 阿里:redis + memcache

文档型数据库(bson和json一样)

  • MongoDB
    • MongoDB是一个基于分布式文件存储的数据库,c++编写,主要用于处理大量的文档
    • MongoDB是一个介于关系型数据库和非关系型数据库中中间的产品! MongoDB 是非关系型数据库中功能最丰富、最像关系型数据库的。
  • ConthDB

列存储数据库

  • HBase
  • 分布式文件系统

图关系数据库

Neo4J、InfoGrid

图结构 存储是各种关系,专注于构建关系图谱。

Redis入门

Redis是什么

Redis(Remote Dictionary Server) 远程字典服务。是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API

Redis 能干啥?
  1. 内存存储、持久化、内存中是断电即失、持久化很重要(rdb、aof)。
  2. 效率高,可用于高速缓存。
  3. 发布订阅系统
  4. 地图信息分析
  5. 计时器、计数器(浏览量)

特性
  1. 多样的数据类型
  2. 持久化
  3. 集群
  4. 事务

官网:https://redis.io/docs/getting-started/

默认端口 6379

Windows使用方法:

  1. 先开启redis-server.exe
  2. 再打开redis-cli.exe

基础知识

一共有16个数据库,默认使用第0个数据库。

flushall //清除所有数据库

flushdb //清除当前数据库

keys * //查看全部数据库的内容
Redis是单线程

Redis是很快的,Redis是基于内存操作,CPU不是Redis性能瓶颈,Redis性能瓶颈是根据机器的内存和网络带宽,可以使用单线程来实现。

Redis是将所有的数据放在内存中,使用单线程操作效率高,多线程(CPU会上下文切换:耗时),对于内存系统而言,没有上下文切换效率高。

Redis-Key
127.0.0.1:6379[3]> keys *
(empty list or set)   //查看库中所有内容
127.0.0.1:6379[3]> set name kang  //存入内容
OK  
127.0.0.1:6379[3]> exists name  //判断元素是否存在
(integer) 1

五大数据类型

String字符串

基础操作

127.0.0.1:6379[3]> set key1 v1  #设置值
OK
127.0.0.1:6379[3]> get key1
"v1"
127.0.0.1:6379[3]> keys *
1) "key1"
2) "name"
127.0.0.1:6379[3]> exists key1  #判断一个key是否存在
(integer) 1
127.0.0.1:6379[3]> append key1 "hello"  #添加字符串 如果当前key不存在,相当于 set key
(integer) 7
127.0.0.1:6379[3]> get key1   #读取某一个key
"v1hello"
127.0.0.1:6379[3]> strlen key1  #获取一个key的长度
(integer) 7

自增操作

127.0.0.1:6379> set views 0 #设置浏览量
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views  #浏览量自增1
(integer) 1 
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> get views    
"2"
127.0.0.1:6379> decr views  #浏览量自减1
(integer) 1
127.0.0.1:6379> incrby views 10 #设置步长  指定增量10
(integer) 11
127.0.0.1:6379> decrby views 10  #设置步长 指定减量10
(integer) 1 

字符串范围

127.0.0.1:6379> set key1 hello,worid
OK
127.0.0.1:6379> get key1  #读取字符串
"hello,worid"
127.0.0.1:6379> getrange key1 0 3  #截取字符串[0,3]
"hell"
127.0.0.1:6379> getrange key1 0 -1   #获取全部的字符串 和 get key是一样的
"hello,worid"

替换字符串

127.0.0.1:6379> set key2 abcdefg
OK
127.0.0.1:6379> get key2
"abcdefg"
127.0.0.1:6379> setrange key2 2 xx   #从指定的位置开始替换
(integer) 7
127.0.0.1:6379> get key2
"abxxefg"

过期时间

#setnx  SET if Not eXists  
#1 如果key被设置了
#0 如果key没有被设置

redis> SETNX mykey "Hello"
(integer) 1
redis> SETNX mykey "World"
(integer) 0

127.0.0.1:6379> setex key3 20 dd  #20s后过期
OK
127.0.0.1:6379> ttl key3  返回key剩余的过期时间
(integer) 13

读写多个值

127.0.0.1:6379> mset key1 v1 key2 v2 key3 v3
OK
127.0.0.1:6379> mget key1 key2 key3
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx  key1 key2 key3 key4
(integer) 0
#对应给定的keys到他们相应的values上。只要有一个key已经存在,MSETNX一个操作都不会执行

存入json格式

127.0.0.1:6379> set user:1 {name:kk,age:4}  #设置一个user:1对象 值为json字符来保存一个对象
OK
127.0.0.1:6379> get user:1  
"{name:kk,age:4}"  

127.0.0.1:6379> mset user:1:name kkk user:1:age 2  #
OK
127.0.0.1:6379>  mget user:1:name user:1:age
1) "kkk"
2) "2"

#getset
127.0.0.1:6379> getset key1 kk
"v1"
127.0.0.1:6379> get key1
"kk"
#自动将key对应到value并且返回原来key对应的value。如果key存在但是对应的value不是字符串,就返回错误。

String类似的使用场景:value除了是我们的字符串还可以是我们的数字

  • 计数器
  • 统计多单位的数量
  • 粉丝数

List列表

Redis中的List其实是链表(Redis使用双端链表实现List)

可以通过List实现栈、队列、阻塞队列。

lpush

127.0.0.1:6379> lpush list 1  #将给定值推入到列表左端
(integer) 1
127.0.0.1:6379> lpush list 2
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "1"

127.0.0.1:6379> rpush list 4
(integer) 4
127.0.0.1:6379> lrange list 0 -1  #获取列表在给定范围上的所有值  从左边向右边读取
1) "3"
2) "2"
3) "1"
4) "4"

127.0.0.1:6379> rpop list #从列表的右端弹出一个值,并返回被弹出的值
"4"
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "2"
3) "1"

lindex

通过索引获取列表元素

#通过索引获取列表中的元素。从0开始计算,也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
127.0.0.1:6379> lindex list 1 
"2"
127.0.0.1:6379> llen list #返回列表的长度
(integer) 3


rpoprpush  #移除列表的最后一个元素(从列表的右端弹出一个值),将它移动到新的列表中


127.0.0.1:6379> lrange list 0 -1  #将列表中指定下标的值替换为指定的值  不存在更新会报错
1) "3"
2) "2"
3) "1"
127.0.0.1:6379> lset list 1 dd
OK
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "dd"
3) "1"

linsert

在值后边插入

127.0.0.1:6379> lrange list 0 -1   
1) "3"
2) "dd"
3) "1"
127.0.0.1:6379> linsert list before dd qq  #在某一个值前面插入
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "qq"
3) "dd"
4) "1"

小结:

  • 如果key不存在,创建新的链表
  • 如果key存在,新增内容
  • 移除了所有的值,空链表,也代表不存在
  • 在两边插入或者改动值,效率最高!中间元素,效率相对低一点

Set集合

Redis的set是string类型的无序集合。集合成员是唯一的,集合中不含有重复数据。

Redis中的集合是通过哈希表实现的,添加、删除、查找的时间复杂度都是 O(1)。

sadd

127.0.0.1:6379> sadd myset "hello" 2
(integer) 2
127.0.0.1:6379> smembers myset
1) "hello"
2) "2"

scard

127.0.0.1:6379> scard myset #获取set集合中的元素个数
(integer) 2

srem

127.0.0.1:6379> srem myset 2  #移除set集合中的指定元素
(integer) 1
127.0.0.1:6379> smembers myset
1) "hello"
127.0.0.1:6379>

spop

随机删除一些set集合中的元素

127.0.0.1:6379> smembers myset
1) "ddd"
2) "dada"
3) "hello"
4) "world"
127.0.0.1:6379> spop myset
"world"
127.0.0.1:6379> spop myset
"hello"
127.0.0.1:6379> spop myset
"ddd"

数字集合类

  • 交集 sinter 共同好友
  • 差集 sdiff
  • 并集 sunion 两人元素之和
127.0.0.1:6379> sadd key1 a
(integer) 1
127.0.0.1:6379> sadd key1 b
(integer) 1
127.0.0.1:6379> sadd key2 a
(integer) 1
127.0.0.1:6379> sdiff key1 key2 #差集
1) "b"
127.0.0.1:6379> sunion key1 key2 #并集
1) "a"
2) "b"
127.0.0.1:6379>  sinter key1 key2 #交集 共同好友
1) "a"

Hash(哈希)

Redis hash是一个String类型的field(字段)和value(值)的映射表,hash特别适合用于存储对象。

hset

127.0.0.1:6379> hset myhash field1 kang
(integer) 1
127.0.0.1:6379>  hget myhash field1
"kang"

hmset

设置多个元素的 field value

127.0.0.1:6379> hmset myhash field2 dada field3 mam   #set多个 key-value
OK
127.0.0.1:6379> hmget myhash field1 field2 field3   
1) "kang"
2) "dada"
3) "mam"
127.0.0.1:6379> hgetall myhash
1) "field1"
2) "kang"
3) "field2"
4) "dada"
5) "field3"
6) "mam"


hdel

删除 field 后,value 也会被删掉

127.0.0.1:6379> hdel myhash field1
(integer) 1
127.0.0.1:6379>  hgetall myhash
1) "field2"
2) "dada"
3) "field3"
4) "mam"

127.0.0.1:6379> hlen myhash  #获取hash表的字段数量!
(integer) 2

127.0.0.1:6379> hkeys myhash  #只获取 field 字段
1) "field2"
2) "field3"
127.0.0.1:6379> hvals myhash #只获取 value 值
1) "dada"
2) "mam"

Zset有序集合

Redis有序集合和集合一样都是String类型元素的集合,不允许重复元素的出现。不同的是每个元素都会关联一个
double类型的分数。redis通过分数来为集合中的成员进行从小到大的排序。

有序集合的成员是唯一的,double类型的分数可以重复。集合通过哈希表实现,删除、查找、添加的复杂度为 O(1)。

zadd

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"

排序的实现

zrangebyscore xxx 负无穷 正无穷

127.0.0.1:6379> zadd salary 2500 hong
127.0.0.1:6379> zadd salary 3000 kang
127.0.0.1:6379> zadd salary 300 wu
127.0.0.1:6379> zrangebyscore salary -inf +inf  #显示全部用户 从小到大
1) "wu"
2) "hong"
3) "kang"

127.0.0.1:6379> zrangebyscore salary -inf +inf withscores  #显示全部用户并附带成绩
1) "wu"
2) "300"
3) "hong"
4) "2500"
5) "kang"
6) "3000"
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores limit 1 2 
1) "hong"
2) "2500"
3) "kang"
4) "3000"

127.0.0.1:6379> zrangebyscore salary -inf 2500 withscores  #显示工资小于2500的员工的升序排序
1) "wu"
2) "300"
3) "hong"
4) "2500"

zrem

127.0.0.1:6379> zrem salary kang   #移除指定的元素
(integer) 1
127.0.0.1:6379> zrange salary 0 -1
1) "wu"
2) "hong"

zcard

127.0.0.1:6379> zcard myset #返回有序集的元素个数  
(integer) 3

zrevrange

返回有序集key中,指定区间内的成员。其中成员的位置按score值递减(从大到小)来排列

127.0.0.1:6379> zrangebyscore salary -inf +inf withscores
1) "wu"
2) "300"
3) "hong"
4) "2500"
127.0.0.1:6379> zrevrange salary 0 -1 
1) "hong"
2) "wu"
127.0.0.1:6379>  zrevrange salary 0 -1 withscores
1) "hong"
2) "2500"
3) "wu"
4) "300"

zcount

返回指定分数范围内的元素个数

127.0.0.1:6379> zcount salary -inf  +inf
(integer) 3

三种特殊的数据类型

geospatial 地理位置

朋友的定位,附近的人,打车距离计算?
在这里插入图片描述

geoadd

# getadd 添加地理位置
# 规则:两级无法直接添加,一般下载城市数据,通过java程序导入。
# 有效的经度从-180度到180度。
# 有效的纬度从-85.05112878度到85.05112878度。
127.0.0.1:6379> geoadd china:city 116.41005  39.9049 beijing
(integer) 1
127.0.0.1:6379> geoadd china:city 121.472644 31.231706 shanghai
(integer) 1

geopos

获取当前的定位,一定是一个坐标

127.0.0.1:6379> geopos china:city beijing  # 获取指定城市的经度和纬度
1) 1) "116.410051882267"
   2) "39.904899707671923"


127.0.0.1:6379> geodist china:city beijing shanghai km  #获取两个经纬度的距离
"1067.4049"

georadius

类似附近的人功能 (获取附近所有的人的地址,定位)通过半径来查询

GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania" # 添加经纬度坐标
(integer) 2

127.0.0.1:6379> GEORADIUS Sicily 15 37 200 km WITHDIST WITHCOORD # 西西里岛200km范围内的坐标 withdist 距离 withcoord 坐标 coordinate (坐标)
1) 1) "Palermo"
   2) "190.4424"
   3) 1) "13.361389338970184"
      2) "38.115556395496299"
2) 1) "Catania"
   2) "56.4413"
   3) 1) "15.087267458438873"
      2) "37.50266842333162"

georadiusbymember
#指定成员的位置被用作查询的中心。

hyperloglog

在这里插入图片描述

什么是基数

基数(不重复的元素)
A {1,3,5,7,8,7}
B{1,3,5,7,8}
B是A的基数集

简介

redis2.8.9版本更新了Hyperloglog,是用来做基数统计的算法

应用场景:一个人访问一个网站多次,还是算作一个人,类似于公众号阅读量

但是需要一定的容错率

测试使用
127.0.0.1:6379> pfadd mykey a b c d e f g # 创建第一组元素 
(integer) 1
127.0.0.1:6379> pfadd mykey2 i j z b n m   # 创建第二组元素
(integer) 1
127.0.0.1:6379> pfcount mykey
(integer) 7
127.0.0.1:6379>  pfcount mykey2
(integer) 6
127.0.0.1:6379>  pfmerge mykey3 mykey mykey2  # 合并两组
OK
127.0.0.1:6379> pfcount mykey3 
(integer) 12

bitmaps 位存储

位存储

统计用户信息,活跃,不活跃。登录,未登录。

Bitmaps,数据结构。都是操作二进制位来记录,只有0和1两个状态。

# 可以用0 1 代替是否打开 然后查看某天是否打卡
127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 1 0
(integer) 0

127.0.0.1:6379> getbit sign 1
(integer) 0

127.0.0.1:6379> bitcount sign  # 查看某个区间数量 可实现判断是否全勤
(integer) 1

事务

Redis事务本质:一组命令的集合。一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行。

一次性、顺序性、排他性!执行一些列的命令。

Redis事务没有隔离级别的概念!

所有的命令在事务中并没有直接被执行!只有发起执行命令的时候才会执行。

Redis单条命令是保存原子性的,但是事务不保证原子性。

Redis的事务:

  • 开启事务(multi)
  • 命令入队
  • 执行事务(exec)

正常执行事务
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> get k2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) "v2"
4) OK
放弃事务
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> discard # 取消事务
OK
127.0.0.1:6379> get k2  # 事务队列中命令都不会被执行
(nil)
编译型异常(代码有问题,命令有错)事务中所有的命令都不会被执行。
127.0.0.1:6379> flushdb
OK
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> 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 k5
(nil)
运行时异常(1/0),如果事务队列中存在语法性,执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常。
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"
监控 watch

悲观锁:

  • 很悲观,认为什么时候都会出问题,无论做什么都加锁。

乐观锁

  • 很乐观,认为什么时候都不会出问题,所以不上锁。更新数据的时候去判断一下,在此期间是否有人修改过这个数据。
  • 获取version
  • 更新的时候比较version

Redis测监视测试

正常执行成功


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
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

如果多线程修改值,使用watch可以当做redis的乐观锁操作!

执行之前如果另一个线程修改了值,事务就会失败。

watch的功能:

如果在 WATCH 执行之后, 事务开始之前, 有其他客户端修改了被监视的 key 的值, 那么当前客户端的事务就会失败。如果 unwatch 取消监视,事务可以正常执行成功。

Jedis

Jedis是使用java操作 redis 的中间件。

  1. 导入对应的依赖
 <!--导入jedis包-->
    <dependencies>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.2.0</version>
        </dependency>
        <!--fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.79</version>
        </dependency>
  1. 编码测试
public class TestPing {

    public static void main(String[] args) {
        //1.new Jedis 对象
        Jedis jedis = new Jedis("127.0.0.1", 6379);

        //2.jedis 所有的命令和redis相同
        System.out.println(jedis.ping());
    }
}

jedis执行事务

public class TestPing {

    public static void main(String[] args) {
        //1.new Jedis 对象
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        jedis.flushDB();

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("hello", "world");
        jsonObject.put("name", "kang");

        Transaction multi = jedis.multi();
        String result = jsonObject.toJSONString();

        try {
            multi.set("user1", result);
            multi.set("user2", result);
            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.close();
        }
    }
}




java.lang.ArithmeticException: / by zero
	at com.kang.TestPing.main(TestPing.java:25)
null
null

Springboot整合

lettuce:采用netty,实例可以在多个线程中共享,不存在线程不安全的情况。可以减少线程数据,更像NIO模式

整合测试

源码分析

	RedisAutoConfiguration
	
	@Bean
	@ConditionalOnMissingBean(name = "redisTemplate")
	@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
	public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
		//默认的 RedisTemplate 没有过多的设置,redis 对象都是需要序列化
		//两个泛型是 Object 的类型,后期需要使用强制转化<String, Object>
		RedisTemplate<Object, Object> template = new RedisTemplate<>();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}

	@Bean
	@ConditionalOnMissingBean //string 是redis中最常使用的类型,单独提出来了一个bean
	@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
	public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
		return new StringRedisTemplate(redisConnectionFactory);
	}
  1. 导入依赖
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
  1. 配置连接
spring.redis.host=127.0.0.1
server.port=6379
  1. 测试
    @Test
    void contextLoads() {
        //redisTemplate
        //opsForValue() 操作字符串 类似String
        //opsForList() 操作List 类似List
        redisTemplate.opsForValue().set("mykey","kangkang");
        System.out.println(redisTemplate.opsForValue().get("mykey"));
    }

序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程

Redis序列化配置的固定模板

@Configuration
public class RedisConfig {

    //编写自己的 redisTemplate
    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory){
       
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);

        //序列化配置
        Jackson2JsonRedisSerializer<Object> objectJackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        objectJackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        //String的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        
        //key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        //hash的key采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        //value序列化方式采用jackson
        template.setValueSerializer(objectJackson2JsonRedisSerializer);
        //hash的value序列化采用jackson
        template.setHashValueSerializer(objectJackson2JsonRedisSerializer);
        return template;
    }
    
}

Redis持久化

Redis是个基于内存的数据库。服务器宕机,内存中的数据将会全部丢失,所以Redis需要实现持久化功能。

RDB(Redis DataBase)

什么是RDB

RDB中文名为快照,RDB持久化是把当前进程数据生成快照保存到磁盘上的过程,由于是某一时刻的快照,快照中的值要早于或等于内存中的值。

触发机制
  1. save的规则满足的情况下,会自动触发rdb规则。
  2. 执行 flushall 命令,也会触发我们的rdb规则!
  3. 退出 redis,也会产生rdb文件。

优点:

  1. 适合大规模的数据恢复。
  2. 对数据的完整性要求不高。

缺点:

  1. 需要一定的时间间隔进行操作!如果redis宕机了,最后一次修改的数据就不存在了。
  2. fork进程的时候,会占用一定的内容空间。

有时候在生产环境中会备份。

AOF(Append Only File)

Redis是“写后”日志,Redis先执行命令,把数据写入内存,然后才记录日志。日志里记录的是Redis收到的每一条命令,这些命令以文本形式保存。PS:大多数数据库采用的是写前日志(WAL),例如MySQL,通过写前日志和两阶段提交,实现数据和逻辑的一致性。

将所有的命令都记录下来

保存的文件是 appendonly.aof文件

优点:

  1. 每一次修改都同步,文件的完整会更好。 appendfsync always
  2. 每秒同步一次,可能会丢失一秒的数据。 appendfsync everysec
  3. 从不同步,效率最高。 appendfsync no

缺点:

  1. 相对于数据文件来说,aof远远大于rdb,修复速度也比rdb慢。
  2. aof运行效率也比rdb慢,redis默认的配置就是rdb持久化。

Redis发布订阅

Redis发布订阅(pub/sub)是一种消息通信模式:发送者发送消息,订阅者接收消息。

Redis客户端可以订阅任意数量的频道。

127.0.0.1:6379> subscribe kang   # 订阅频道 接收消息
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "kang"
3) (integer) 1
1) "message"
2) "kang"
3) "666"


127.0.0.1:6379> publish kang 666  # 向指定频道发送消息
(integer) 1

Redis主从复制

主从复制,读写分离!80%的情况都是在进行读操作!减缓服务器的压力!

默认情况下,每台redis服务器都是主节点。

127.0.0.1:6379> info replication   # 查看当前库的信息
# Replication
role:master  # 角色 master
connected_slaves:0  # 没有从机
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

复制配置文件,修改对应信息

  1. 端口
  2. pid名字
  3. log文件名字
  4. dump.rdb 名字

主机可以写,从机不能写,只能读。

主机断开连接,从机依旧连接到主机的,但是没有写操作,如果主机回来了,从机依旧可以直接获取到主机写的信息!

如果使用命令行来配置的主从,这个时候如果重启了,从机就会变成主机!但是变为从机时,立刻就可以从主机中获取值。

哨兵模式

Redis Sentinel,即Redis哨兵。哨兵的核心功能就是主节点的自动故障转移。谋朝篡位的自动版,自动称为主节点。

Redis缓存穿透和雪崩

缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求。(查不到)

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。(量太大,缓存过期)


参考视频:https://www.bilibili.com/video/BV1S54y1R7SB?spm_id_from=333.999.0.0

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值