如何建自己网站做淘宝客,建设一个微商的网站,学校网站建设如何分类,网站销售如何做业绩1. 什么是NoSql
NoSQL一词最早出现于1998年#xff0c;是Carlo Strozzi开发的一个轻量、开源、不提供SQL功能的关系数据库。2009年#xff0c;Last.fm的Johan Oskarsson发起了一次关于分布式开源数据库的讨论#xff0c;来自Rackspace的Eric Evans再次提出了NoSQL的概念是Carlo Strozzi开发的一个轻量、开源、不提供SQL功能的关系数据库。2009年Last.fm的Johan Oskarsson发起了一次关于分布式开源数据库的讨论来自Rackspace的Eric Evans再次提出了NoSQL的概念这时的NoSQL主要指非关系型、分布式、不提供ACID的数据库设计模式。它不同于传统的关系数据库两者存在许多显著的不同点其中最重要的是NoSQL不使用SQL作为查询语言。其数据存储可以不需要固定的表格模式。
2. Redis简介
2008年意大利的一家创业公司Merzia推出了一款基于MySQL的网站实时统计系统LLOOGG然而没过多久该公司的创始人 Salvatore Sanfilippo便对MySQL的性能感到失望于是他决定亲自为LLOOGG量身定做一个数据库并于2009年开发完成这个数据库就是Redis。 不过Salvatore Sanfilippo并不满足只将Redis用于LLOOGG这一款产品而是希望更多的人使用它于是在同一年Salvatore Sanfilippo将Redis开源发布并开始和Redis的另一名主要的代码贡献者Pieter Noordhuis一起继续着Redis的开发直到今天。短短的几年时间Redis就拥有了庞大的用户群体。Hacker News在2012年发布了一份数据库的使用情况调查结果显示有近12%的公司在使用Redis。国内如新浪微博、街旁网、知乎网国外如GitHub、Stack Overflow、Flickr等都是Redis的用户。VMware公司从2010年开始赞助Redis的开发 Salvatore Sanfilippo和Pieter Noordhuis也分别在3月和5月加入VMware全职开发Redis。
Redis是使用c语言开发的一个高性能键值数据库。常用于分布式系统中的缓存、电商秒杀、排行榜、访问量统计、分布式会话共享等高并发应用场景。Redis可以通过一些键值类型来存储数据。其数据类型包括字符类型、散列类型、列表类型、集合类型、有序集合类型。
3. 安装Redis
访问Redis官网https://redis.io/download下载最新的版本 。 解压并编译安装
$ tar xzf redis-5.0.3.tar.gz
$ cd redis-5.0.3
$ make installRedis官网并没有提供windows版本但可以前往https://github.com/tporadowski/redis/releases下载windows的个人编译版本注意并不是最新的版本。 4. 启动服务
4.1 前端启动
在redis的src目录有一个redis-server文件用于启动一个redis服务。 redis的默认端口为6379当客户端需要连接到redis服务时就通过服务端的IP地址以及这个端口进行连接。也可以修改这个默认端口。在redis的根目录下有一个redis.conf文件它是redis的核心配置文件redis的所有配置信息都在此文件中。如果需要修改端口我们在配置文件中找到port配置并将6379改为其他的端口号。 修改完后需要重新启动redis服务需要注意的是在使用redis-server启动服务时需要指定redis.conf文件的绝对路径否则redis将以默认的配置启动一个服务实例。 前端启动的模式我们可以在终端看到redis的启动信息和相关的操作日志但此时如果关闭了终端或者使用controlc将会立即停止redis服务。
4.2 后端启动
所谓后端启动就是以一个独立的进程来运行一个redis服务。首先修改redis.conf文件找到daemonize选项并设置为yes如下图 保存退出后重新启动redis服务此时redis将以后台进程的方式启动服务。终端没有显示相关的启动信息并且启动完成后终端可以继续执行其他的操作。 5. 客户端连接
5.1 Redis客户端
在redis的src目录下有一个redis-cli命令这个就是官方提供的redis客户端可以使用它来连接和操作redis。当然这仅仅只是一个命令行的客户端程序在实际的开发中会有不同的平台语言因此官网也提供了对各种语言的客户端实现在实际的项目开发中使用不同语言的客户端来操作redis。例如官网提供了一个Java的客户端Jedis。 1使用redis-cli
可以使用使用官方自带的redis-cli客户端来连接redis服务。参数-h为连接redis服务器的IP地址-p为redis的端口号。连接完成后就可以对redis进行操作了。 2退出客户端
如果想要退出客户端的连接只需要在连接的状态下输入quit或者exit即可。 3身份认证
默认连接Redis时是不需要认证密码的我们可以为其设置一个连接的认证密码。首先在redis.conf中找到requirepass配置项取消注释并设置一个密码。 保存后重启服务在连接客户端时加上-a参数并输入配置的密码。 连接时也可以不指定密码也可以正常连接但在操作Redis时候会提示一个错误要求输入认证密码。这时使用auth命令来输入密码即可。 5.2 可视化客户端
也可以使用第三方的redis的可视化客户端RDMredis-desktop-manager它同时提供了各种系统平台的编译版本安装后即可使用。下载地址 点击左上角的Connect to Redis Server在弹出的窗口中填写相关的Name连接名称、Address连接地址、端口号以及认证密码Auth点击OK即可。 这里我们看到连接redis后默认有16个库0 ~ 15这是redis默认的配置可以在redis.conf中可以找到相应的选项并修改默认数量。 当我们使用客户端连接redis时默认选择的是index为0的数据库然而也可以使用select命令选择其他数据库。例如选择index为15的数据库如下操作 5.3. 停止服务
如果使用前端启动redis可以使用controlc或者kill命令来杀掉进程的方式关闭redis注意controlc并不能停止后端启动的redis但这些方式都是强制性的关闭redis由于redis保存的数据先会存储在内存如果此时强制关闭将导致redis还没将数据持久化到文件中就退出可能会照成部分的数据丢失。因此应该使用正常的退出方式来停止redis服务正常退出redis同样使用redis-cli工具。 如果设置了认证密码在关闭服务端时也同样需要指定。 6. 数据类型及常用API
Redis支持五种数据类型string字符串hash哈希list列表set集合及sorted set(zset有序集合)。
6.1 string字符串
String 是 redis 最基本的类型一个 key 对应一个 value。它是二进制安全的可以包含任何数据如jpg图片或者序列化的对象。
1SET
语法set key value
赋值操作。 2GET
语法get key
取值操作。 3GETSET
语法getset key value
取值后重新赋值。 4MSET
语法mset key value [key value …]
同时设置多个键值。 5MGET
语法mget key [key …]
获取多个键值。 6DEL
语法del key [key …]
删除一个或多个键值对。 7INCR
语法incr key
当存储的字符串是整数时让当前键值递增并返回递增或增加后的值。 8INCRBY
语法incrby key increment*
当存储的字符串是整数时让当前键值增加指定的数值并返回递增或增加后的值。 9DECR
语法decr key
让当前键值递减并返回递减或减少后的值。 10DECRBY
语法decrby key decrement
让当前键值减少指定的数值并返回递减或减少后的值。 11APPEND
语法append key value
向键值的末尾追加value。如果键不存在则将该键的值设置为value即相当于 SET key value。返回值是追加后字符串的总长度。 12获取字符串长度STRLEN
STRLEN命令返回键值的长度如果键不存在则返回0。 6.2 hash哈希
hash是一个string类型的field和value的映射表而field只能是String类型hash特别适合用于存储对象。 1HSET
语法HSET key field value
HSET一次只能设置一个字段值。HSET命令不区分插入和更新操作当执行插入操作时HSET命令返回1当执行更新操作时返回0。 2HSETNX
语法HSETNX key field value
当字段不存在时赋值类似HSET。区别在于如果字段存在该命令不执行任何操作。
例如hsetnx user name zing
说明如果user中不存在name字段则设置name的值为zing否则不做任何操作。 3HGET
语法HGET key field
HGET一次只能获取一个字段值。 4HGETALL
语法HGETALL key
获取所有字段值。 5HDEL
语法HDEL key field [field…]
可以删除一个或多个字段返回值是被删除的字段个数。 6HINCRBY
语法HINCRBY key field increment
为某个字段增加数值。 7HEXISTS
语法HEXISTS key field
判断字段是否存在存在则返回1否则返回0。 8HKEYS
语法HKEYS key
获取所有的字段名。 9HVALS
语法HVALS key
获取所有字段的值。 10HLEN
语法HLEN key
获取字段数量。 6.3 list列表
Redis的list是采用来链表来存储的所以对于Redis的list数据类型的操作是操作list的两端数据来操作的。
1LPUSH
语法LPUSH key value [value …]
向列表左边添加元素。 2RPUSH
语法RPUSH key value [value …]
向列表右边添加元素。 3LRANGE
语法LRANGE key start stop
LRANGE命令是列表类型最常用的命令之一用于获取列表中的某一片段将返回start到stop之间的所有元素包含两端的元素索引从0开始。索引可以是负数如-1代表最后边的一个元素。 4LPOP
语法LPOP key
LPOP命令从列表左边弹出一个元素会分两步完成第一步是将列表左边的元素从列表中移除。第二步是返回被移除的元素值。 5RPOP
语法RPOP key
RPOP命令从列表右边弹出一个元素步骤与LPOP类似第一步是将列表右边的元素从列表中移除。第二步是返回被移除的元素值。 6LLEN
语法LLEN key
获取列表中元素的个数 7LREM
语法LREM key count value
LREM命令会删除列表中前count个值为value的元素返回实际删除的元素个数。根据count值的不同该命令的执行方式会有所不同
当count0时 LREM会从列表左边开始删除。
当count0时 LREM会从列表右边开始删除。
当count0时LREM删除所有值为value的元素。 8LINDEX
语法LINDEX key index
获得指定索引的元素值。 9LSET
语法LSET key index value
设置指定索引的元素值。 10LTRIM
语法LTRIM key start stop
只保留列表的指定片段 11LINSERT
语法LINSERT key BEFORE|AFTER pivot value
LINSERT首先会在列表中从左到右查找值为pivot的元素然后根据第二个参数是BEFORE还是AFTER来决定将value插入到该元素的前面还是后面。 12RPOPLPUSH
语法RPOPLPUSH source destination
将一个列表的最后一个元素转移到另一个列表的最前面 6.4 set集合
Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的这就意味着集合中不能出现重复的数据。
1SADD
语法SADD key member [member …]
增加一个或多个元素。 2SREM
语法SREM key member [member …]
移除一个或多个元素。 3SMEMBERS
语法SMEMBERS key
获得集合中的所有元素。 4SISMEMBER
语法SISMEMBER key member
判断元素是否存在集合中。存在返回1否则返回0。 5SDIFF
语法SDIFF key [key …]
查找属于集合A并且不属于集合B的元素。差集运算 6SINTER
语法SINTER key [key …]
查找属于集合A且属于集合B的元素。交集运算 7SUNION
语法SUNION key [key …]
查找属于集合A或者属于集合B的元素。合并运算 8SCARD
语法SCARD key
获取集合中元素的个数。 9SPOP
语法SPOP key [count]
从集合中弹出一个或多个元素由count指定。如果不指定count默认弹出一个。由于集合是无序的所有SPOP命令会从集合中随机选择一个元素弹出。 6.5 zset有序集合
zset又称sorted set称之为有序集合可排序的但是唯一。和set的不同之处在于zset会给集合中的元素添加一个分数然后通过这个分数进行排序。
1ZADD
语法ZADD key score member [score member …]
向有序集合中加入一个或多个元素和该元素的分数如果该元素已经存在则会用新的分数替换原有的分数。返回值是新加入到集合中的元素个数不包含之前已经存在的元素。 2ZSCORE
语法ZSCORE key member
获取元素的分数。 3ZREM
语法ZREM key member [member …]
移除有序集合中的一个或多个成员不存在的成员将被忽略。 4ZRANGE
语法ZRANGE key start stop [WITHSCORES]
按照元素分数从小到大的顺序返回索引从start到stop之间的所有元素包含两端的元素。如果需要获得元素的分数可以在命令尾部加上WITHSCORES参数。 5ZREVRANGE
语法ZREVRANGE key start stop [WITHSCORES]
按照元素分数从大到小的顺序返回索引从start到stop之间的所有元素包含两端的元素。如果需要获得元素的分数的可以在命令尾部加上WITHSCORES参数。 6ZRANK
语法ZRANK key member
获取元素排名从小到大。 7ZREVRANK
语法ZREVRANK key member
获取元素排名从大到小。 8ZRANGEBYSCORE
语法ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
获得指定分数范围的元素。 9ZINCRBY
语法ZINCRBY key increment member
增加某个元素的分数并返回更改后的分数。 10ZCARD
语法ZCARD key
获取集合元素的数量。 11ZCOUNT
语法ZCOUNT key min max
获取指定分数范围内的元素个数。 12ZREMRANGEBYRANK
语法ZREMRANGEBYRANK key start stop
按照排名范围删除元素。 13ZREMRANGEBYSCORE
语法ZREMRANGEBYSCORE key min max
按照分数范围删除元素。 7. Redis键Keys
Redis键是二进制安全的这意味着你可以使用任何二进制序列作为键从像”foo” 这样的字符串到一个 JPEG文件的内容。空字符串也是合法的键。
7.1 键的一些设计规则 不要使用太长的键。例如不要使用一个1024字节的键不仅是因为占用内存而且在数据集中查找key时需要多次耗时的key比较。 不要使用太短的key。例如user:1001比u1001更具有实际意义相对于key本身以及value对象来说增加的空间微乎其微。当然短的键会消耗少的内存需要找到平衡点。 规范一种模式 (schema)。用冒号或者下横线来连接多单词字段例如”user:1001”或者user_1001。
7.2 Key的常用API
1KEYS
语法keys pattern
返回指定pattern的所有key 2EXISTS
语法exists key
判断一个key是否存在。存在返回后1否则返回0。 3RENAME
语法rename key newkey
重命名key 4TYPE
语法type key
根据key返回value的类型。 5EXPIRE
语法expire key seconds
设置key的生存时间。Redis的数据是缓存在内存中的然后很多时候数据一般都会设置一个过期时间即到期后销毁数据从而释放更多的内存。过期时间默认以秒为单位默认值为-1表示永不过期。 也可以在设值的时候指定过期时间秒 6TTL
语法ttl key
查看key剩余的过期时间。 7PERSIST
语法persist key
清除key的过期时间。 8PEXPIRE
语法pexpire key
以毫秒为单位设置key的过期时间。 也可以在设值的时候指定过期的时间毫秒 8. 持久化
8.1 简介
Redis是一个支持持久化的内存数据库可以将内存中的数据同步到磁盘保证持久化。我们知道Redis会将数据缓存在内存中如果没有持久化在服务器关闭或重启之后数据会丢失。为了保证数据的安全以及效率Redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件。而Redis提供了RDB和AOF两种持久化策略。
8.2 RDB
Redis默认是会以快照RDB的形式将数据持久化到磁盘的一个dump.rdb二进 制文件。当Redis决定要持久化时会 fork 一个子进程将数据写到磁盘上一个临时的RDB文件中当子进程完成写操作后将原来的RDB替换掉。而Redis会在满足某些条件后会进行持久化并且可以对其进行配置。
配置RDB
在redis.conf文件中找到“Save the DB on disk”的配置我们可以根据需要来修改这Redis的RDB持久化策略。 说明
save 900 1如果在900秒之内有1次操作则执行快照保存
save 300 10如果在300秒内有10次操作则执行快照保存
save 60 10000如果在1分钟之内有10000个次操作则执行快照保存
SAVE和BGSAVE
我们可以在客户端直接使用SAVE或者BGSAVE命令立即将Redis的数据持久化到RDB文件中。他们两者的区别在于BGSAVE命令会fork一个子进程在后台进行持久化主进程可以继续处理客户端发送的命令非阻塞。而SAVE命令需要等待Redis持久化完成后才可以继续处理客户端发送的命令阻塞。 **RDB优点 **
RDB非常适合用于数据备份 可以在当天内每小时备份一次或者每个月的每天都进行备份。 如果遇到断电或者宕机等其他一些灾难情况可以随时将数据集还原。
RDB缺点
如果对数据的完整性和安全性要求非常高要求每一次的操作数据都能持久化到文件中这时RDB就不太适合了。因为RDB是按照时间范围的操作次数为条件促发持久化如果未满足这些触发条件Redis并不会将数据保存到文件导致数据丢失。例如save 60 10000如果在1分钟之内有9000次的操作如果此时服务器异常退出或宕机由于未满足条件将导致丢失这1分钟的数据。
8.3 AOF
AOF持久化可以记录每个写操作将Redis执行过的所有写指令读操作不记录保存到appendonly.aof文件中并且只允许追加文件而不可以改写文件。在Redis启动的时候会读取该文件重新构建缓存数据。在打开AOF持久化机制之后Redis每当接收到一条写命令会先写入系统缓存然后每隔一定时间默认是每秒钟fsync一次写入到指定文件。
启用AOF
AOF持久化默认是关闭的如果要启用AOF需要在redis.conf配置文件中启用该功能将appendonly no设置为appendonly yes。 所有写操作默认保存在appendonly.aof文件中可以自行修改保存的路径和文件名。 同步策略
AOF提供了三种同步策略
always每次写操作就执行一次fsynceverysec每秒执行一次fsync默认no不执行fsync AOF重写
AOF会记录Redis所有的写操作命令但这种方式会造成一个问题就是随着时间的推移大量频繁的操作将导致AOF文件体积的急剧增长对系统会造成影响。为了解决以上的问题 Redis就需要对AOF文件进行重写。重写的过程会创建一个新的AOF文件来代替原有的AOF文件 而新AOF文件和原有AOF 文件保存的数据状态是一致的但新文件的体积将变得尽可能地小。以下两种方式会触发AOF重写。
1手动出发
在客户端直接向Redis发送BGREWRITEAOF命令这个命令会通过移除AOF文件中的冗余命令来重写rewriteAOF文件。 2自动触发
其实在启用了AOF之后appendonly yesRedis会依据redis.conf配置文件中的auto-aof-rewrite-percentage选项和auto-aof-rewrite-min-size选项来自动执行BGREWRITEAOF命令。 说明
例如设置了auto-aof-rewrite-percentage为100和auto-aof-rewrite-min-size为64mb那么当AOF文件的体积大于64MB时并且AOF文件的体积比上一次重写之后的体积大一倍100%的Redis将执行BGREWRITEAOF命令进行重写。
AOF优点
AOF弥补了RDB按照时间范围的操作次数为条件的缺点即使在默认的策略中发生故障最多也只会丢失一秒钟的数据更大程度的保证了数据的安全性。
AOF缺点
AOF会保存每一次的写操作这将导致AOF文件的体积通常要大于RDB文件。如果选用always策略则表示每一次操作都会记录到AOF文件中从性能的角度上来说会低于RDB。当然使用默认的everysec策略进行持久化性能还是非常可观的。
8.4 混合持久化
在实际应用中通常会同时使用RDB和AOF两种持久化来找到一个最佳的平衡点即能保证性能的同时最大程度保证数据的安全。因此需要RDB和AOF两者同时进行合理的设置和调整。而从Redis 4.0开始官方提供了一种更加方便的混合持久化配置。
未启用混合持久化
在未启用混合持久化之前如果我们往Redis写入一条记时RDB文件会保存操作的键值数据AOF文件则保存的是写操作的指令我们可以分别查看一下这两个文件的内容。
使用cat命令查看RDB文件 然而显示的内容并不太直观也不易理解因此可以借助Redis提供的redis-check-rdb工具进行查看。 RDB文件中会保存Redis的相关信息以及存储的keys数量和相关的活期时间。接下来我们继续查看AOF文件的内容直接使用cat命名进行查看。 结果显示AOF文件中保存的是相关的操作指令。
混合持久化
要使用混合持久化除了在redis.conf文件中启用AOF将appendonly设置为yes还需要将aof-use-rdb-preamble设置为yes。 设置完重新启用Redis服务。启用了混合持久化之后使用BGREWRITEAOF命令执行一次AOF重写同时向Redis插入一条新的数据。 然后再次使用cat命令再次查看AOF文件这时会发现启用混合持久化之后的AOF文件内容和未启用时的AOF文件内容不一样。这是因为此时产生的AOF文件是一个RDB-AOF的混合文件Redis会基于某种协议将此文件的前半部分存储RDB的数据后半部分存储的是AOF的操作命令。 9. 事务
Redis事务可以一次执行多个命令批量命令操作并且是一个单独的隔离操作。事务中的所有命令都会按顺序地执行。事务在执行的过程中不会被其他客户端发送来的命令请求所打断。
9.1 事务操作
Redis事务主要由MULTI 、 EXEC、DISCARD、WATCH和UNWATCH这些基础命令构成。
1MULTI
语法MULTI
用于标记事务的开始后续客户端执行的命令都将被存入一个命令队列直到执行EXEC时这些命令才会被执行。 2EXEC
语法EXEC
执行命令队列中的所有命令但如果在启用一个事务之前执行了WATCH命令那么只有当WATCH所监控的keys没有被修改的前提下EXEC命令才能执行事务队列中的所有命令并返回所有命令的执行结果否则EXEC将放弃当前事务中的所有命令。 3DISCARD
语法DISCARD
取消事务队列中的所有命令并将当前连接的状态恢复为非事务状态。如果WATCH命令被使用会自动执行UNWATCH取消监视的所有keys。 4WATCH
语法WATCH key[key…]
WATCH命令类似于关系型数据库的乐观锁可以在启用事务之前监视某些keys的变化。在MULTI命令执行之前可以指定需要监视的keys在执行EXEC之前如果被监控的keys发生修改EXEC将放弃执行该队列中的所有指令。并且WATCH命令可以监控一个或多个键一旦其中有一个键被修改或删除之后的事务就不会执行。
首先打开一个客户端并使用watch命令监视user:1001的key接着使用multi启用事务。 然后打开第二个客户端并修改key为user:1001的value为user01。 最后回到第一个客户端再次对key为user:1001的value修改为user001并执行exec命令。由于user:1001这个key被第一个客户端所监视而这个key在启用事务前被第二个客户端修改了因此当第一个客户端启用事务后再对其进行修改时这是无效的Redis将放弃队列中的所有指令返回了(nil)。 5UNWATCH
语法WATCH key[key…]
取消当前事务中指定监控的keys。如果执行了EXEC或DISCARD命令则无需再手工执行该命令了因为在此之后UNWATCH命令会自动执行事务中所有的keys都将自动取消监控。 9.2 原子性
在关系型数据库中的原子性代表一系列不可分割的操作要么全部执行成功要么全部不执行。如果执行过程中产生了错误或者异常那么事务将会自动回滚。而在Redis的事务中是否具备原子性呢我们看看以下两种情况并得出相关的结论。
错误指令
在使用multi命令开启事务之后然后输入一些命令其中包含一个错误的命令。 从结果来看似乎有点符合我们对事务的理解。但仔细想想这只是在输入命令的时候产生语法的错误Redis对其进行了校验报错之后Redis就放弃了这个事务。因此得出的结论是Redis在启用事务输入操作命令时是原子操作它会对命任何一个命令进行语法检查当输入有误时Redis会清空队列并放弃事务。
运行时错误
如果输入的命令都正确而在执行这些命令时产生了错误Redis是否会取消所有命令并放弃事务呢看下面的例子。 当执行到第二条命令时产生了错误用户名不是一个整型数值并不能自增但是前面和后面的命令都执行成功。并不会因为执行了一个错误的命令而回退所有已经执行成功的命令并放弃整个事务。因此得出的结论是Redis在执行命令队列时并不是原子性的通俗点说就是Redis本身并不支持事务的回滚机制。
10. Java客户端
10.1 使用Lettuce
Lettuce是Redis的一个java客户端同类的产品还有Jedis。但在多线程的环境下使用Jedis是非线程安全的。而Lettuce的连接对象是基于Netty在多线程并发访问时是线程安全的并且单个连接对象可以满足多线程并发访问的要求。Lettuce还支持同步、异步、反应式、发布/订阅等多种通信方式。
添加依赖
dependencygroupIdio.lettuce/groupIdartifactIdlettuce-core/artifactIdversion5.2.2.RELEASE/version
/dependency编写LettuceUtils
public class LettuceUtils {private static StatefulRedisConnection connection;static {RedisURI redisURI RedisURI.Builder.redis(localhost).withPort(6379).withPassword(123456).withDatabase(0).withTimeout(Duration.ofSeconds(5)).build();connection RedisClient.create(redisURI).connect();}/*** Sync* return*/public static RedisCommands getCommands() {return connection.sync();}/*** Async* return*/public static RedisAsyncCommands getAsyncCommands(){return connection.async();}/*** Reactive* return*/public static RedisReactiveCommands getReactiveCommands(){return connection.reactive();}
}示例
Test
public void testGetAndSet(){RedisCommandsString, String commands LettuceUtils.getCommands();commands.set(key, Hello, Redis!);String value commands.get(key);System.out.println(value);
}参考https://www.baeldung.com/java-redis-lettuce 11 整合Spring Boot
添加依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId
/dependency
dependencygroupIdcom.fasterxml.jackson.core/groupIdartifactIdjackson-databind/artifactId
/dependencyyml配置
spring:# redis配置redis:# 指定使用第几个库默认是0database: 0# 主机地址host: 127.0.0.1# 端口port: 6379# 认证密码如果在redis.conf中配置了密码password: wangl# 连接超时时间timeout: 2000
# 连接池配置
# lettuce:
# pool:
# # 最大连接数
# max-active: 10
# # 最大空闲连接
# max-idle: 8
# # 最小空闲连接
# min-idle: 5
# # 建立连接最大等待时间
# max-wait: 2000
# # 每间隔多少毫秒运行一次空闲连接回收
# time-between-eviction-runs: 60000由于Lettuce的连接是基于Netty的一个连接对象StatefulRedisConnection就可以满足多线程环境下的并发访问许多场景是不需要配置连接池的。如果在特定场景下需要用到连接池那么在yml进行添加lettuce pool的配置需要依赖commons-pool2。
dependencygroupIdorg.apache.commons/groupIdartifactIdcommons-pool2/artifactId
/dependency10.1 使用RedisTemplate
我们可以在类中直接注入一个StringRedisTemplatekey和value都为String类型它继承自RedisTemplate。
Autowired
private StringRedisTemplate stringRedisTemplate;示例
Test
void testForValue() {//添加stringRedisTemplate.opsForValue().set(user:1001, user1);//依据key获取valueString name stringRedisTemplate.opsForValue().get(user:1001);System.out.println(name);//删除stringRedisTemplate.delete(user:1001);
}Spring提供了多种Operations接口来对不同的数据结构进行操作以下是常见的接口
接口获取方式说明ValueOperationsredisTemplate.opsForValue()操作字符串ListOperationsredisTemplate.opsForList()操作ListSetOperationsredisTemplate.opsForSet()操作SetZSetOperationsredisTemplate.opsForZSet()操作ZSetHashOperationsredisTemplate.opsForHash()操作Hash
示例
stringRedisTemplate.opsForList().leftPush(list,user1);
stringRedisTemplate.opsForList().rightPush(list,user2);参考https://www.jianshu.com/p/7bf5dc61ca06 自定义序列化器
StringRedisTemplate操作的key和value都是字符串如果我们需要存储其他类型的数据那么可以自定义key和value的序列化器来装配一个RedisTemplate。
编写配置类
Configuration
public class RedisConfig {/*** 自定义RedisTemplate,指定key和value的序列化器* param connectionFactory* return*/Beanpublic RedisTemplateString, Object redisTemplate(RedisConnectionFactory connectionFactory){//创建RedisTemplate实例RedisTemplateString, Object redisTemplate new RedisTemplate();//使用StringRedisSerializer作为key的序列化器StringRedisSerializer keySerializer new StringRedisSerializer();redisTemplate.setKeySerializer(keySerializer);redisTemplate.setHashKeySerializer(keySerializer);//使用Jackson2JsonRedisSerializer作为value的序列化器GenericJackson2JsonRedisSerializer valueSerializer new GenericJackson2JsonRedisSerializer()redisTemplate.setValueSerializer(valueSerializer);redisTemplate.setHashValueSerializer(valueSerializer);redisTemplate.setConnectionFactory(connectionFactory);return redisTemplate;}} spring提供了多种序列化器以下列出常见的Serializer
序列化器说明StringRedisSerializer简单的字符串序列化GenericToStringSerializer可以将任何对象泛化为字符串并序列化GenericJackson2JsonRedisSerializer使用Jackson将对象序列化为JSON字符串JdkSerializationRedisSerializer使用JDK提供的序列化功能
示例
//注入redisTemplate
Autowired
private RedisTemplateString, Object redisTemplateTest
void test2(){Users user new Users();user.setId(1001);user.setUserName(user1);user.setAge(21);redisTemplate.opsForValue().set(user:1001, user);Users u (Users) redisTemplate.opsForValue().get(user:1001);log.info(u.getUserName());
}10.2 使用缓存Cache
除了使用RedisTemplate还可以使用Spring提供的Spring Cache来操作Redis。Spring Cache是一个非常灵活的缓存解决方案对众多的缓存框架进行了统一的封装当底层使用不同的缓存框架时由对应的缓存管理器来进行管理。Spring 3.1内置了五个缓存管理器
SimpleCacheManagerNoOpCacheManagerConcrrentMapCacheManagerCompositeCacheManagerEhCacheCacheManager
Spring 3.2引入了另外的一个缓存管理器这个缓存管理器可以在基于JCacheJSR-107的缓存提供商之中。除了核心的Spring框架Spring data又提供了两个缓存管理器。
RedisCacheManager 来自于Spring-data-redis项目GemfireCacheManager 来自于Spring-data-GemFire项目
所以我们选择缓存管理器时候取决于使用底层缓存供应商
10.2.1 启用缓存
在配置类上添加EnableCaching
Configuration
EnableCaching
public class RedisConfig {...
}10.2.2 配置缓存管理器
这里底层使用的Redis作为缓存技术因此需要装配RedisCacheManager这个缓存管理器。
Configuration
EnableCaching
public class RedisConfig {/*** 装配RedisCacheManager这里初始化了cache1和cache2两个缓存并存入Map中,* 后续在使用时可以指定操作哪一个缓存。* param redisConnectionFactory* return*/Beanpublic RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {MapString, RedisCacheConfiguration map new HashMap(2);map.put(cache1, initRedisCacheConfiguration(1800L));map.put(cache2, initRedisCacheConfiguration(3600L));RedisCacheManager cacheManager RedisCacheManager.builder(redisConnectionFactory).withInitialCacheConfigurations(map).build();return cacheManager;}/*** Redis缓存配置配置相关的key和value序列化器以及缓存过期时间* serializeKeysWith()方法用于设置key的序列化器* serializeValuesWith()方法用于设置value的序列化器* entryTtl()方法用于设置过期时间* param ttl* return*/private RedisCacheConfiguration initRedisCacheConfiguration(Long ttl) {RedisCacheConfiguration cacheConfiguration RedisCacheConfiguration.defaultCacheConfig();return cacheConfiguration//设置key的序列化器.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))//设置value的序列化器.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))//设置缓存过期时间.entryTtl(Duration.ofSeconds(ttl));}
} 我们可以创建多个缓存实例如cache1、cache2并对这些缓存做相关的配置比如设置缓存key和value的序列化器以及指定缓存的活期时间等等。在使用时可以指定要将数据放入哪个缓存实例中最后将这些缓存实例纳入缓存管理器中管理。
10.2.3 缓存注解
Spring 3.1 引入了基于注释的缓存技术通过少量的配置 annotation 注释即可使得既有代码支持缓存。
Cacheable
该注解标记在一个方法上时表示该方法是支持缓存的当标记在一个类上时则表示该类所有的方法都是支持缓存的。对于一个支持缓存的方法Spring会在其标注的方法调用后将其返回值缓存起来以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果而不需要再次执行该方法。
示例
Service
public class UserInfoServiceImpl {Autowiredprivate UserInfoDaoImpl dao;//这里指定的缓存名为cache1,与配置中的名字一样,缓存的过期时间为1800//如果指定的不是配置中的名字,就会使用默认的配置,比如过期时间是-1(永不过期)Cacheable(value cache1,key #id)public UserInfo getUser(Integer id) {UserInfo result dao.getById(id);return result;}}在业务类方法上使用Cacheable注解当执行完此方法后会将dao返回的结果保存在缓存中。如果下次传入相同id查询时会从缓存获取不会再次调用getUser方法。
Cacheable主要属性
参数说明示例value缓存的名称在配置类中定义必须指定至少一个Cacheable(value”cache1”) 或者 Cacheable(value{”cache1”,”cache2”}key缓存的key可以为空如果指定就要按照SpEL表达式编写如果不指定则缺省按照方法的所有参数进行组合Cacheable(value”cache1”,key”#userName”)condition缓存的条件可以为空使用SpEL编写返回true或者false只有为true才进行缓存Cacheable(value”cache1”, key”#userName” condition”#userName.length()2”)unless用来排除缓存,返回true的时候不放在缓存中Cacheable(value“cache1”, key“#id”, unless“#resultnull”) 表示方法返回值为null时不放置在缓存中
key的生成策略
spring缓存中的key是按照一定规则来生成的默认情况下是Cacheable注解中value属性的值加上:: 再加上key属性的值来生成key。例如
Cacheable(valueabc,key#id)
public UserInfo getById(Integer id)如果调用getById方法时传入的参数为100那么最终生成的key就是abc::100
自定义key的生成策略
我们也可以在装配RedisCacheConfiguration时设置key生成策略例如
RedisCacheConfiguration initRedisCacheConfiguration(Long ttl) {RedisCacheConfiguration cacheConfiguration RedisCacheConfiguration.defaultCacheConfig();return cacheConfiguration//设置key的序列化器.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))//设置value的序列化器.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))//设置缓存过期时间.entryTtl(Duration.ofSeconds(ttl));设置缓存key的前缀cacheName的值由Cacheable注解的value属性决定.computePrefixWith(cacheName - demo.concat(:).concat(cacheName).concat(:));}
} 上面调用RedisCacheConfiguration的computePrefixWith方法来设置key的前缀此时再去调用getById方法时最终生成的key为demo:abc:100。
key表达式
Cacheable的key属性支持SpringEL表达式,这里的EL表达式可以使用方法参数及它们对应的属性。使用方法参数时我们可以直接使用“#参数名”或者“#p加上参数下标”。例如
Cacheable(valueusers, key#id)
public User getUser(Integer id) {return dao.getUserById(id);
}Cacheable(valueusers, key#p0)
public User getUser(Integer id) {return dao.getUserById(id);
}Cacheable(valueusers, key#user.id)
public User getUser(User user) {return dao.getUserById(user.getId());
}Cacheable(valueusers, key#p0.id)
public User getUser(User user) {return dao.getUserById(user.getId());
} 除了上述使用方法参数作为key之外Spring还为我们提供了一个root对象可以用来生成key。通过该root对象我们可以获取到以下信息。
属性名称说明示例methodName当前方法名#root.methodNamemethod当前方法#root.method.nametarget当前被调用的对象#root.targettargetClass当前被调用对象的class#root.targetClassargs当前方法参数组成的数组#root.args[0]caches当前被调用的方法使用的Cache名称#root.caches[0].name
示例
Cacheable(valueusers, key#root.methodName)
public User getUser(Integer id) {return dao.getUserById(id);
}此时将使用当前方法名作为缓存的key。
CachePut
CachePut标注的方法在执行前不会去检查缓存中是否存有缓存的数据而是每次都会执行该方法并将执行结果再次保存到指定的缓存中相当于覆盖缓存。
示例
CachePut(value cache1,key #user.id)
public UserInfo insert(User user) {dao.insert(userInfo);return user;
}Cacheable主要属性
属性说明value缓存的名称在配置类中定义必须指定至少一个key缓存的key可以为空如果指定就要按照SpEL表达式编写如果不指定则缺省按照方法的所有参数进行组合condition缓存的条件可以为空使用SpEL编写返回true或者false只有为true才进行缓存
CachEvict
该注解根据一定的条件对缓存进行清空
示例
CacheEvict(valuecache1, key#id)
public void deleteById(Integer id) {dao.deleteById(id);
}Cacheable主要属性
属性说明value缓存的名称在配置类中定义必须指定至少一个key缓存的key可以为空如果指定就要按照SpEL表达式编写如果不指定则缺省按照方法的所有参数进行组合condition缓存的条件可以为空使用SpEL编写返回true或者false只有为true才进行缓存allEntries是否清空所有缓存内容缺省为 false如果指定为 true则方法调用后将立即清空所有缓存beforeInvocation是否在方法执行前就清空缺省为 false如果指定为 true则在方法还没有执行的时候就清空缓存缺省情况下如果方法执行抛出异常则不会清空缓存