Redis

1

参考

《Redis设计与实现》 遇见狂神说

NoSql概述

单机MySQL的年代
Memcached(缓存)+Mysql+垂直拆分(读写分离)
分库分表+水平拆分+MySQL集群
NoSQL not only sql不仅仅是数据库,泛指非关系型数据库。传统的关系型数据
库无法应对大数据,NoSQL在当今大数据时代发展瞬速。很多的数据类型比如用户
的个人信息、社交网络、地理位置等并不需要一个固定的格式,不需要多余的操作
就可以横向扩展

横向扩展和纵向扩展

横向扩展:多增加几台API服务器,一起服务。也叫水平扩展,用更多的节点支撑更
大量的请求。 如成千上万的蚂蚁完成一项搬运工作
纵向扩展:把API服务器换成性能更好的机器。又叫垂直扩展,扩展一个点的能力支
撑更大的请求。如利用1个人的能力,如蜘蛛侠逼停火车

NoSql特点

  1. 方便扩展,数据之间没有关系
  2. 大数据高性能(Redis一秒写8万,读取11万)缓存记录级、细粒度
  3. 数据类型是多样型的,不需要事先设计数据库,随取随用
  4. 不仅仅保存数据
  5. 没有固定的查询语言
  6. 键值对存储、列存储、文档存储、图形数据库
  7. 最终一致性
  8. CAP定理(一致性(Consistency)、可用性(Availability)、分区容错性,
    这三个要素最多只能同时实现两点)和BASE(基本可用(Basically Available)
    软状态(Soft state)最终一致(Eventually consistent))
  9. 高性能、高可用、高可扩
  10. 关系型数据库特点
  • 结构化组织
  • SQL
  • 数据和关系都存储在单独的表中
  • 有专门的数据操作以及数据定义语言
  • 严格的一致性原则

NoSQL四大分类

  1. KV键值对
  • Redis
  1. 文档型数据库 boson格式,和json一样
  • MongoDB 基于分布式文件存储的数据库,主要用来处理大量文档,是介于
    关系型数据库和菲关系型数据库之间的产品
  • ConthDB
  1. 列存储数据库
  • HBase
  • 分布式文件系统
  1. 图关系数据库
  • Neo4j
  • InfoGrid

Redis概述

Remote Dictionary Server,即远程字典服务

  1. 内存存储,持久化(rdb aof)
  2. 效率高,可以用于高速缓存
  3. 发布订阅系统
  4. 地图信息分析
  5. 计时器

Linux下载Redis

我在VMware虚拟机中创建centos,用xhell远程连接
如果有网络问题请参考 https://www.bbsmax.com/A/rV57Qk3jzP/
下载Redis压缩文件,通过pscp从windows系统传送到Linux系统
注意最新的版本也就是6开头的话gcc的版本也要是最新的,这里我用了旧版本
pscp -r D:\shared\redis-5.0.10.tar.gz root@IP:/opt

Redis配置

进入Redis-5.0.10可以查看所有文件,redis.conf是配置文件
安装 yum install gcc-c++ ,Redis是用C++写的
安装完成后执行 make & make install
Redis的默认安装路径在/usr/local/bin
cp /home/ming/redis-5.0.10/redis.conf kconfig 将配置文件复制一份
编辑redis.conf文件,将daemonize改为yes,默认后台启动
启动redis
关闭redis

测试性能

redis-benchmark是一个压力测试工具
比如现在来测试100个并发连接和100000个请求
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
对100000个请求进行写入测试,一共有100个并发客户端,每次写入3个字节,
只有一台服务器处理这些请求,每秒能够处理51255.77个请求

Redis

以上的所有操作都能完成后就可以正式学习Redis了

基础知识

Redis默认有16个数据库,可以查看redis.conf文件,默认使用的是第0个
数据库

1
2
3
4
5
select index #index就是指定使用哪个数据库
dbsize #查看当前数据库的大小
keys * #查看所有的key
flushdb #清空数据库
flushall #清空所有数据库

Redis是单线程的,Redis是基于内存操作,CPU不是Redis的性能瓶颈,Redis
的瓶颈是根据机器内存和网络带宽,既然可以使用单线程就使用了呗。Redis是
用C语言写的,官方提供的数据为100000+的QPS,Redis有以下误区

  1. 高性能服务器一定是多线程?
  2. 多线程一定比单线程效率高?

Redis是将所有的数据全部放入内存中,所以使用单线程是最快的,因为多线程
会存在CPU上下文切换耗时

五大基本数据类型

通过官方介绍可以知道Redis可以用作数据库、缓存和消息中间件MQ。支持多种
类型的数据结构 string,hashes,lists,sets,sorted sets和范围查询,
bitmaps,hyperloglogs和地理空间索引半径查询

Redis-Key

1
2
3
4
5
move key 1 #将key移动到指定数据库
del key #删除键
expire key 10 #key在10s后过期
ttl key #可以查看key还有几秒过期
type key #查看类型

String

1
2
3
4
5
6
7
8
getrange key start end #查看从start到end的字符串,从0开始如果end为-1则为全部
setrange key start xx #从start开始将字符串替换为xx,替换的长度就是xx的长度
setex key time value #设置值的同时设置过期时间
setnx key xx #如果当前key不存在的时候进行创建,如果存在则创建失败,在分布式锁中使用
mset k1 v1 k2 v2 #批量设置
mget k1 k2 k3 #批量获取
msetnx k1 v1 k2 v2 #k1 k2必须都不存在才设置成功,原子性操作
getset key xx #如果不存在key则返回null否则获取之前值设置新的值

三大特殊类型

geospatial

这个功能可以推算地理位置的信息,两地之间的距离,方圆几里的人。底层原理是Zset

1
2
3
4
5
6
7
8
9
10
geoadd china:city 114.109 22.544 shenzhen
geoadd china:city 121.445 31.213 shanghai
geoadd china:city 106.50 29.53 chongqing
geoadd china:city 116.40 39.90 beijing
geopos china:city beijin chongqing #获取经纬度
geodist china:city shenzhen shanghai #获取两地之间的距离
#以某个地点为圆心半径为1000的所有地点
georadius china:city 110 30 1000 km withdist withcoord count
georadiusbymember china:city shenzhen 1000 km
geohash china:city shenzhen #将经纬度转换为一个字符串

Hyperloglog

占用的内存是固定的

1
2
3
pfadd key xx #添加元素,重复的元素实际上不会成功添加
pfcount key #统计不重复的元素数量
pfmerge key key2 key3 #将key2和key3的元素合并放入key

Bitmap

位存储,比如每天打卡就可以使用0或1来表示

1
2
3
4
setbit key offset value
setbit sign 0 1 #这就可以表示星期一打卡
getbit key offset
bitcount key

事务

Redis单条命令是具有原子性的,但是Redis的事务是不具有原子性的

  1. 开启事务使用 multi
  2. 命令入队 所有操作先不执行,只有发起执行命令才会执行
  3. 执行命令 exec 一次性、顺序性、排他性
  4. 取消事务 discard 之前入队的操作都不会被执行

对于一个事务,如果这个事务中存在错误命令等情况,所有命令都不会被执行,
如果命令没错但是运行时出现错误,其余正确的操作依然可以正常运行

Redis实现乐观锁

  • 悲观锁:认为什么时候都会出问题,无论做什么都会加锁
  • 乐观锁:认为什么时候都不会出问题,无论做什么都不加锁。更新数据的时候
    会判断一下数据是否被修改,如果数据被修改则更新失败

现在开启两个线程,一开始money为80,在新建会话8中监视money并开启事务,
此时先不执行事务,在新建会话7中修改money为1000,然后在会话8中执行事
务,可以看到事务执行失败,watch可以当做redis的乐观锁操作,unwatch
可以解锁放弃监视

Redis配置文件详解

Redis启动的时候就通过配置文件来启动

  1. 默认单位 配置文件unit单位对大小写不敏感
    1
    2
    3
    4
    5
    6
    7
    8
    # 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.
  2. 可以包含多个配置文件
    1
    2
    # include /path/to/local.conf
    # include /path/to/other.conf
  3. 网络
    1
    2
    bind 127.0.0.1 #默认在本地访问
    port 6379
  4. 通用配置
    1
    2
    3
    4
    5
    6
    7
    8
    9
    daemonize yes #以守护进程的方式运行
    pidfile /var/run/redis_6379.pid #如果以后台方式运行就需要指定一个pid文件
    databases 16 #默认有16个数据库
    #redis是内存数据库,如果没有持久化那么数据断点即失
    save 900 1 #如果900s内至少有一个key被修改就进行持久化操作
    save 300 10 #300s内至少10个key被修改则进行持久化操作
    save 60 10000 #60s内有至少10000个key被修改则进行持久化操作
    stop-writes-on-bgsave-error yes #持久化出错是否还要继续工作
    rdbcompression yes #是否压缩rdb文件,需要消耗一些CPU资源
  5. 安全
    Redis默认是没有密码的,可以通过set requirepass xxx 来设置,登录的
    时候 auth xxx 输入密码即可
    1
    # requirepass foobared
  6. 限制
    1
    2
    3
    4
    最多10000个客户端连接过来
    maxclients 10000
    maxmemory <bytes> #可以配置的最大内存
    maxmemory-policy noeviction #内存到达上限之后的处理策略
  7. aof配置
    1
    appendonly no #默认不开启,默认使用rdb持久化

RDB

之前就已经提过,Redis是内存数据库,如果不将内存中的数据库状态保存
到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失,所
Redis提供了持久化功能
在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是Snapshot快
照,它恢复时是将快照文件直接读到内存里。Redis会单独创建一个子进程
来进行持久化,先会将数据写到一个临时文件中,等持久化过程都结束了,
再用这个临时文件替换上次持久化好的文件,整个过程主进程不进行任何
IO操作,这就确保极高的性能。如果需要对大规模数据进行恢复,且对于
数据恢复的完整性不是非常敏感,那么RDB就比AOF更加高效,RDB的缺
点是最后一次持久化的数据可能丢失

  • 优点 适合大规模的数据恢复,对数据的完整性要求不高
  • 缺点 需要一定时间间隔进程操作

AOF

将所有命令都记录下来,恢复的时候就把这个文件全部都执行一遍
以日志的形式记录每个写操作,将Redis执行过的所有命令记录下来(读
操作不记录),只许追加文件但不可以改写文件,Redis启动之初会读取
该文件重新构建数据,也就是说Redis重启的话就根据日志文件的内容将
写指令从前到后执行一次以完成数据的恢复工作

Redis是什么?

Redis本质上是一个Key-Value 类型的内存数据库,很像memcached,整个数
据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到
硬盘上进行保存

Redis的优缺点?

  1. 优点
  • 因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过10万次读
    写操作,是已知性能最快的Key-Value DB
  • 支持保存多种数据结构,此外单个value的最大限制是1GB,不像memcached
    只能保存1MB的数据,因此Redis可以用来实现很多有用的功能
  1. 缺点
  • 是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此
    Redis适合的场景主要局限在较小数据量的高性能操作和运算上

关系型数据库和非关系型数据库的区别?

  1. 数据存储结构 关系型数据库一般都有固定的表结构,比如基于文档的,K-V
    键值对的,还有基于图的等,对于数据的格式十分灵活没有固定的表结构,方
    便扩展
  2. 可扩展性 关系型数据库横向扩展难,不好对数据进行分片等,而一些非关
    系型数据库则原生就支持数据的水平扩展(比如mongodb的sharding机制)
  3. 数据一致性 非关系型数据库一般强调的是数据最终一致性,而不没有像
    ACID 一样强调数据的强一致性,从非关系型数据库中读到的有可能还是处
    于一个中间态的数据,因此如果你的业务对于数据的一致性要求很高,那么
    非关系型数据库并不一个很好的选择,非关系型数据库可能更多的偏向于
    OLAP(联机分析处理)场景,而关系型数据库更多偏向于OLTP场景

横向扩展和纵向扩展的区别?

  1. 横向扩展:多增加几台API服务器,一起服务。也叫水平扩展,用更多的节
    点支撑更大量的请求。 如成千上万的蚂蚁完成一项搬运工作
  2. 纵向扩展:把API服务器换成性能更好的机器。又叫垂直扩展,扩展一个点
    的能力支撑更大的请求。如利用1个人的能力,如蜘蛛侠逼停火车

Redis为什么这么快?

  1. 完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存
    中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)
  2. 数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的
  3. 采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者
    多线程导致的切换而消耗CPU,不用去考虑各种锁的问题,不存在加锁释放锁操
    作,没有因为可能出现死锁而导致的性能消耗
  4. 使用多路I/O复用模型,非阻塞IO
  5. 使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协
    议不一样,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的
    话,会浪费一定的时间去移动和请求

Redis相比memcached有哪些优势?

  1. redis支持更丰富的数据类型(支持更复杂的应用场景):Redis不仅仅支持
    简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储
    。memcache支持简单的数据类型,String
  2. Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候
    可以再次加载进行使用,而Memecache把数据全部存在内存之中。
  3. 集群模式:memcached没有原生的集群模式,需要依靠客户端来实现往集
    群中分片写入数据,但是 redis 目前是原生支持 cluster 模式的
  4. Memcached是多线程,非阻塞IO复用的网络模型;Redis使用单线程的多路
    IO 复用模型

Redis 的数据类型?

Redis 支持五种数据类型:string(字符串),hash(哈希),list(列表)
,set(集合)及 zset sorted set:有序集合

  1. string:redis 中字符串 value 最大可为512M。可以用来做一些计数功
    能的缓存(也是实际工作中最常见的)。 常规计数:微博数,粉丝数等
  2. list:简单的字符串列表,按照插入顺序排序,可以添加一个元素到列表
    的头部(左边)或者尾部(右边),Redis list的实现为一个双向链表,即
    可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销。可
    以实现一个简单消息队列功能,做基于redis的分页功能等。可以通过lrange
    命令,就是从某个元素开始读取多少个元素,可以基于list 实现分页查询,
    类似微博那种下拉不断分页,微博的时间轴
  3. set:是一个字符串类型的无序集合。可以用来进行全局去重等。(比如:在
    微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存
    在一个集合。Redis可以非常方便的实现如共同关注、共同粉丝、共同喜好等功
    能。这个过程也就是求交集的过程)
  4. sorted set:是一个字符串类型的有序集合,给每一个元素一个固定的分
    数score来保持顺序。可以用来做排行榜应用或者进行范围查找等
  5. hash:键值对集合,是一个字符串类型的Key和 Value 的映射表,也就是
    说其存储的Value是一个键值对(Key- Value)hash 特别适合用于存储对象
    ,后续操作的时候,你可以直接仅仅修改这个对象中的某个字段的值。 比如
    我们可以 hash 数据结构来存储用户信息,商品信息等等

Redis三大特殊类型?

geospatial Hyperloglog Bitmap

  1. geospatial 这个功能可以推算地理位置的信息,两地之间的距离,方圆几
    里的人
  2. Hyperloglog 用来做基数统计的算法,占用的内存是固定的,因为其只会
    根据输入元素来计算基数,而不会储存输入元素本身,基数=不重复元素的个
    数。一个人访问了一个网站多次,但是还是算作一个人
  3. 通过一个bit位来表示某个元素对应的值或者状态,可以用来统计用户信息
    ,登陆,未登录,打卡

Redis的常用场景?

  1. 计数器 可以对String 进行自增自减运算,从而实现计数器功能。Redis
    这种内存型数据库的读写性能非常高,很适合存储频繁读写的计数量
  2. 排行榜 集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操
    作的时候变的非常简单,Redis 只是正好提供了这两种数据结构
  3. 会话缓存 可以使用 Redis 来统一存储多台应用服务器的会话信息。当应用
    服务器不再存储用户的会话信息,也就不再具有状态,一个用户可以请求任意
    一个应用服务器,从而更容易实现高可用性以及可伸缩性

redis 持久化机制是什么?

Redis提供了两种不同的持久化方法可以将数据存储在磁盘中,一种叫快照RDB,
另一种叫只追加文件AOF

  1. RDB 在指定的时间间隔内将内存中的数据集快照写入磁盘(Snapshot),它
    恢复时是将快照文件直接读到内存里。Redis 会单独创建(fork)一个子进程来
    进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再
    用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何
    IO 操作的,这就确保了极高的性能如果需要进行大规模数据的恢复,且对于
    数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB
    的缺点是最后一次持久化后的数据可能丢失
  • 优点 适合大规模的数据恢复 对数据完整性和一致性要求不高
  • 缺点 在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢
    失最后一次快照后的所有修改
  1. AOF 以日志的形式来记录每个写操作,将Redis 执行过的所有写指令记录
    下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读
    取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写
    指令从前到后执行一次以完成数据的恢复工作。
    AOF保存的是appendonly.aof文件,采用文件追加方式,文件会越来越大为避
    免出现此种情况,新增了重写机制,当AOF文件的大小超过所设定的阈值时,
    Redis 就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集
  • 优点 每次发生数据变更会被立即记录到磁盘,性能较差但数据完整性比较好

redis 底层的数据结构?

有8种底层数据结构

  1. string 字符串对象的编码可以是int、raw或者embstr,如果一个字符串的
    内容可以转换为long,那么该字符串就会被转换成为long类型,对象的ptr就
    会指向该 long,并且对象类型也用 int 类型表示。普通的字符串有两种,
    embstr和raw。。如果字符串对象的长度小于39字节,就用embstr对象。否
    则用传统的raw对象
  2. 哈希对象 ziplist或者hashtable
  3. 列表对象 ziplist或者linkedlist
  4. 集合对象 intset或者hashtable,intset是一个整数集合,里面存的为
    某种同一类型的整数
  5. 有序集合对象 一种是ziplist,另一种是skiplist与dict的结合

Redis 常见命令?

  1. string get 、 set 、 del 、 incr、 decr
  2. Hash hget 、hset 、 hdel
  3. List
  • lpush+lpop=Stack(栈)
  • lpush+rpop=Queue(队列)
  • lpush+ltrim=Capped Collection(有限集合)
  • lpush+brpop=Message Queue(消息队列)
  1. Set sset 、srem、scard、smembers、sismember
  2. zset zadd 、 zrange、 zscore

跳跃表是什么?

  1. 跳表全称为跳跃列表,它允许快速查询,插入和删除一个有序连续元素的
    数据链表。跳跃列表的平均查找和插入时间复杂度都是O(logn)
  2. 快速查询是通过维护一个多层次的链表,且每一层链表中的元素是前一层
    链表元素的子集,本质是对链表加多级索引
  3. 一开始时,算法在最稀疏的层次进行搜索,直至需要查找的元素在该层两
    个相邻的元素中间。这时,算法将跳转到下一个层次,重复刚才的搜索,直到
    找到需要查找的元素为止

字符串类型是怎么实现的?

  1. 在redis的字符串类型对象中,底层都是采用的是简单动态字符串SDS
    数据结构来实现
  2. SDS 也叫简单动态字符串
  3. C 字符串中他本身不记录自身的长度信息,所有为了获取一个C字符串的
    长度,程序必须遍历整个字符串,对每个字符进行计数,直到遇到空字符为
    止,时间复杂度O(N)。和C字符串相比SDS在len属性中记录了字符串本身的
    长度信息,因此获取SDS长度的时间复杂度O(1),这极大程度上提高了性能
  4. C字符串还会容易产生缓冲区溢出,SDS的空间分配完全杜绝了发生缓冲
    区溢出的可能性

分布式锁是什么?

为了防止分布式系统中的多个进程之间相互干扰,我们需要一种分布式协调
技术来对这些进程进行调度。而这个分布式协调技术的核心就是来实现这个
分布式锁

分布式锁应该具备哪些条件?

  1. 在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行
  2. 高可用的获取锁与释放锁
  3. 高性能的获取锁与释放锁
  4. 具备可重入特性
  5. 具备锁失效机制,防止死锁
  6. 具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败

分布式锁的实现有哪些

  1. Memcached:利用 Memcached 的 add 命令。此命令是原子性操作,只有
    在key 不存在的情况下,才能add 成功,也就意味着线程得到了锁
  2. Redis:和 Memcached 的方式类似,利用 Redis 的setnx 命令。此命令
    同样是原子性操作,只有在key 不存在的情况下,才能set 成功
  3. Zookeeper:利用 Zookeeper 的顺序临时节点,来实现分布式锁和等待
    队列。Zookeeper 设计的初衷,就是为了实现分布式锁服务的
  4. Chubby:Google 公司实现的粗粒度分布式锁服务,底层利用了Paxos
    一致性算法

Redis 实现分布式锁?

  1. 加锁 使用SETNX指令插入一个键值对,如果Key 已经存在,那么会返回
    False,否则插入成功并返回 True,说明key 原本不存在,该线程成功得
    到了锁
  2. 当得到锁的线程执行完任务,需要释放锁,以便其他线程可以进入。释放
    锁的最简单方式是执行del 指令
  3. 锁超时 如果一个得到锁的线程在执行任务的过程中挂掉,来不及显式地
    释放锁,这块资源将会永远被锁住(死锁),别的线程再也别想进来。所以
    ,setnx 的key 必须设置一个超时时间,以保证即使没有被显式释放,这
    把锁也要在一定时间后自动释放。setnx 不支持超时参数,所以需要额外
    的指令 expire

Kafka 是什么?

  1. Kafka 是一款基于发布与订阅的消息系统。它一般被称为“分布式提交日
    志”或者“分布式流平台”。
  2. kafka的目标是实现一个为处理实时数据提供一个统一、高吞吐、低延迟
    的平台

Jedis

Jedis是官方推荐的Java连接开发工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.11.2</version>
</dependency>

连接redis,如果连接不成功尝试关闭防火墙,反正情况很多
systemctl stop firewalld.service

1
2
3
4
5
6
7
8
9
10
11
12
public class Test {
public static void main(String[] args) {
Jedis jedis=new Jedis("192.168.8.11",6379);
//所有的api命令就是对应redis命令
System.out.println("判断某个键是否存在"+jedis.exists("money"));
System.out.println(jedis.set("username","kuangshen"));
Set<String> keys=jedis.keys("*");
System.out.println(keys);
System.out.println(jedis.del("username"));
System.out.println(jedis.flushDB());
}
}

事务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static void main(String[] args) {
Jedis jedis=new Jedis("192.168.8.11",6379);
Map<String,String> map=new HashMap<>();
map.put("hello","world");
map.put("name","kuangshen");
//开启事务
Transaction multi = jedis.multi();
try {
multi.set("user1", map.toString());
multi.set("user2",map.toString());
int i=1/0;
//事实上以下这句根本就没有执行
multi.exec();
}catch (Exception e){
multi.discard();
e.printStackTrace();
}finally {
System.out.println(jedis.get("user1"));
jedis.close();

}
}

SpringBoot整合Redis

底层由jedis替换成了lettuce

  • jedis 采用的直连,多个线程操作是不安全的
  • lettuce 采用netty,实例可以在多个线程中共享,不存在线程不安全的情况
    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    配置连接
    1
    2
    spring.redis.host=localhost
    spring.redis.port=6379
    RedisTemplate可以操作不同的数据类型,api和Redis指令是对应的
    1
    2
    redisTemplate.opsForValue().set("user","fsd");
    redisTemplate.opsForvalue().get("user");

自定义RedisTemplate

redis不能直接保存没有序列化的对象,所有对象都需要序列化或者通过jackson
转换成字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
	@Test
public void contextLoads() throws JsonProcessingException {
User user=new User("你好",2);
String jsonUser=new ObjectMapper().writeValueAsString(user);
redisTemplate.opsForValue().set("user",jsonUser);
System.out.println(redisTemplate.opsForValue().get("user"));

}
public class User implements Serializable {
public String name;
public int age;
public User(String name,int age){
this.name=name;
this.age=age;
}
}

默认的序列化是JDK的序列化,可以自定义序列化方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Configuration
public class RedisConfig {
@Bean
@SuppressWarnings("all")
public RedisTemplate<String,Object> redisTemplate(
RedisConnectionFactory factory){
//一般直接使用<String,Object>
RedisTemplate<String,Object> template=new RedisTemplate<>();
template.setConnectionFactory(factory);
//Json序列化配置
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer=
new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om=new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
//String的序列化
StringRedisSerializer stringRedisSerializer=new StringRedisSerializer();
//key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
//hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
//value的序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
//hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
Author: 高明
Link: https://skysea-gaoming.github.io/2020/02/29/Redis/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.