Instalación del entorno Linux y explicación detallada del uso de redis

Redis

 

1. Introducción a NoSQL

NoSQL ( Not Only SQL ), que significa no solo SQL , generalmente se refiere a bases de datos no relacionales. Nosql, una categoría técnica, se propuso en los primeros días y la tendencia se hizo cada vez más alta en 2009.

2. ¿Por qué NoSQL?

Con el auge de los sitios web de Internet, las bases de datos relacionales tradicionales se han vuelto incapaces de manejar sitios web dinámicos, especialmente sitios web puramente dinámicos de gran escala y alta concurrencia, lo que expone muchos problemas insuperables. Por ejemplo, las consultas frecuentes de datos de productos en el sitio web del centro comercial , las estadísticas de clasificación de los productos de búsqueda más populares , el problema de las horas extra de pedidos y el almacenamiento de WeChat Moments (audio y video) son muy complicados de usar en bases de datos relacionales tradicionales, aunque correspondiente Funcional pero no tan optimista en términos de rendimiento. La aparición de nosql, una categoría técnica, resuelve mejor estos problemas y le dice al mundo que no se trata solo de sql.

3. Cuatro categorías de NoSQL

3.1 Base de datos de almacenamiento de valores clave

# 1. Descripción:
-Este tipo de base de datos utiliza principalmente una tabla hash, que tiene una clave específica y un puntero a datos específicos.
# 2. Características
- La ventaja del modelo clave/valor para sistemas TI es que es simple y fácil de implementar.
-Pero si el DBA solo consulta o actualiza algunos valores, la clave/valor es ineficiente.
# 3. Productos relacionados
- Gabinete de Tokio/Tirano,
-Redis _
- SSDB
-Voldemort _
- Oráculo BDB

3.2 Base de datos del almacén de columnas

# 1. Descripción
- Esta parte de la base de datos se suele utilizar para tratar datos masivos almacenados en forma distribuida.
# 2. Características
- Las claves aún existen, pero se caracterizan por apuntar a múltiples columnas. Las columnas están organizadas por familia de columnas.
# 3. Productos relacionados
- Cassandra, HBase, Ripple.

3.3 Base de datos de documentos

# 1. Descripción
-La base de datos de documentos está inspirada en el software de oficina Lotus Notes y es similar al primer almacén clave-valor, este tipo de modelo de datos es un documento versionado y los documentos semiestructurados se almacenan en un formato específico, como JSON. . Una base de datos de documentos puede verse como una versión mejorada de una base de datos de valores-clave, que permite valores-clave anidados. Y la eficiencia de las consultas de la base de datos de documentos es mayor que la de la base de datos de valores clave.
# 2. Características
- Almacenado como un documento
# 3. Productos relacionados
- MongoDB, CouchDB, MongoDb(4.x) También existe SequoiaDB, una base de datos de documentos en China, que ha sido de código abierto.

3.4 Base de datos de gráficos

# 1. Descripción
-La base de datos estructurada en gráficos se diferencia de otras bases de datos SQL de estructura rígida y de columnas de filas: utiliza un modelo de gráfico flexible y se puede extender a múltiples servidores.
- No existe un lenguaje de consulta estándar (SQL) para bases de datos NoSQL, por lo que es necesario formular un modelo de datos para consultas de bases de datos. Muchas bases de datos NoSQL tienen una interfaz de datos RESTful o una API de consulta.
# 2. Características
# 3. Productos relacionados
- Neo4J, InfoGrid, Gráfico Infinito,

4. Escenarios de aplicación NoSQL

  • El modelo de datos es relativamente simple.
  • Necesidad de sistemas informáticos más flexibles
  • Altos requisitos de rendimiento de la base de datos.
  • No requiere un alto grado de coherencia de los datos.

5. ¿Qué es Redis?

Redis es un almacén de estructura de datos en memoria de código abierto (con licencia BSD), que se utiliza como base de datos, caché y intermediario de mensajes.
El código abierto de Redis sigue el almacenamiento de datos basado en memoria BSD y se utiliza como middleware de mensajes de caché de base de datos
  • Resumen: redis es una base de datos en memoria

6. Funciones de Redis

  • Redis es una base de datos en memoria de clave/valor de alto rendimiento
  • Redis admite tipos de datos enriquecidos
  • Redis apoya la persistencia
  • Redis de un solo hilo, de un solo proceso

7. Instalación de Redis

#0. Preparar el ambiente
-vmware15.x +
-centos7.x +
# 1. Descargue el paquete fuente de Redis
-Redis _
# 2. Descargue el paquete fuente completo
- redis-4.0.10.tar.gz
# 3. Cargue el paquete de datos de Redis descargado en Linux
# 4. Descomprime el archivo
[root@localhost ~]# tar -zxvf redis-4.0.10.tar.gz
[raíz@localhost ~]#ll
# 5. Instalar gcc
- yum instalar -y gcc
# 6. Ingrese al directorio de descompresión y ejecute el siguiente comando
- hacer MALLOC=libc
# 7. Ejecute el siguiente comando después de compilar
- hacer instalar PREFIX=/usr/redis
# 8. Ingrese al directorio /usr/redis para iniciar el servicio redis
- ./redis-servidor
# 9. El puerto de servicio predeterminado de Redis es 6379
# 10. Ingrese al directorio bin para realizar operaciones de conexión del cliente
- ./redis-cli -h dirección IP -p puerto redis
./redis-cli -h localhost -p 6379
# 11. La conexión es exitosa y aparece la interfaz anterior y la conexión es exitosa

8. Instrucciones relacionadas con la base de datos de Redis

8.1 Instrucciones de operación de la base de datos

# 1. Descripción de la biblioteca de Redis
- Después de usar el configurador predeterminado de Redis para activar el servicio de Redis, habrá 16 bibliotecas de forma predeterminada, numeradas del 0 al 15.
- Puede utilizar el número de la biblioteca seleccionada para seleccionar una biblioteca de Redis
# 2. Instrucciones para operar bibliotecas en Redis
- Vaciar la biblioteca actual FLUSHDB
- Vaciar todas las bibliotecas FLUSHALL
# 3. El cliente redis muestra chino, obtenga la clave, si está en chino, inicie sesión en redis de la siguiente manera para mostrar chino
- ./redis-cli -p 7000 --raw

8.2 Comandos relacionados con las teclas de operación

# 1.DEL instrucción del
- Sintaxis: tecla DEL [tecla...]
- Función: Eliminar una o más claves dadas. Las claves que no existen se ignoran.
- Versiones disponibles: >= 1.0.0
- Valor de retorno: el número de claves eliminadas.
# 2.EXISTS指令 existe
- Sintaxis: clave EXISTE
- Rol: comprobar si la clave proporcionada existe.
- Versiones disponibles: >= 1.0.0
- Valor de retorno: si la clave existe, devuelve 1; de lo contrario, devuelve 0.
# 3.EXPIRAR expirar
- Sintaxis: EXPIRE segundos clave
- Función: establece la vida útil (segundos) de una clave determinada; cuando la clave caduque (la vida útil es 0), se eliminará automáticamente.
- Versiones disponibles: >= 1.0.0
- Complejidad del tiempo: O(1)
- Valor de retorno: se devuelve 1 si la configuración se realiza correctamente.
# 4.TECLAS TECLAS
- Sintaxis: patrón LLAVES
- Función: busque todas las claves que coincidan con el patrón dado.
- gramática:
KEYS * coincide con todas las claves de la base de datos.
TECLAS hola coincide con hola, hola, hxllo, etc.
TECLAS hola coincide con hola y heeeeello, etc.
TECLAS h[ae]llo coincide con hola y hola, pero no con hillo. Los símbolos especiales están separados por "\"
- Versiones disponibles: >= 1.0.0
- Valor de retorno: una lista de claves que coinciden con el patrón dado.
# 5.MOVER movimiento
- Sintaxis: MOVE clave db
- Función: Mover la clave de la base de datos actual a la base de datos dada.
- Versiones disponibles: >= 1.0.0
- Valor de retorno: se devuelve 1 si el movimiento tiene éxito y 0 si falla.
# 6.PEXPIRE pexpire
- Sintaxis: clave PEXPIRE milisegundos
- Función: este comando es similar al comando EXPIRE, pero establece la vida útil de la clave en milisegundos, no en segundos como el comando EXPIRE.
- Versiones disponibles: >= 2.6.0
- Complejidad del tiempo: O(1)
- Valor de retorno: si la configuración es exitosa, devuelve 1; si la clave no existe o la configuración falla, devuelve 0
# 7.PEXPIREAT peexpireat
- Sintaxis: clave PEXPIREAT milisegundos-marca de tiempo
- Función: este comando es similar al comando EXPIREAT, pero establece la marca de tiempo Unix de vencimiento de la clave en milisegundos en lugar de segundos como EXPIREAT.
- Versiones disponibles: >= 2.6.0
- Valor de retorno: si la configuración de duración es exitosa, devuelve 1. Cuando la clave no existe o no hay forma de establecer la vida útil, devuelve 0. (consulte el comando EXPIRE para obtener más información)
# 8.TTL ttl
- Sintaxis: clave TTL
- Función: Devuelve la vida útil restante (TTL, tiempo de vida) de la clave dada en segundos.
- Versiones disponibles: >= 1.0.0
- valor de retorno:
Devuelve -2 cuando la clave no existe.
Devuelve -1 cuando la clave existe pero no se establece ninguna vida útil restante.
De lo contrario, devuelve la vida útil restante de la clave en segundos.
- Nota: Antes de Redis 2.8, cuando la clave no existe o no le queda vida útil, el comando devuelve -1.
# 9.PTTL pttl
- Sintaxis: clave PTTL
- Función: este comando es similar al comando TTL, pero devuelve la vida útil restante de la clave en milisegundos en lugar de segundos como el comando TTL.
- Versiones disponibles: >= 2.6.0
- Valor de retorno: cuando la clave no existe, devuelve -2. Devuelve -1 cuando la clave existe pero no se establece ninguna vida útil restante.
- De lo contrario, devuelve la vida útil restante de la clave en milisegundos.
- Nota: Antes de Redis 2.8, cuando la clave no existe o no se establece la vida útil restante de la clave, el comando devuelve -1.
# 10.RANDOMKEY clave aleatoria
- Sintaxis: RANDOMKEY
- Función: Devuelve aleatoriamente (no elimina) una clave de la base de datos actual.
- Versiones disponibles: >= 1.0.0
- Valor de retorno: cuando la base de datos no está vacía, devuelve una clave. Devuelve nulo cuando la base de datos está vacía.
# 11.RENOMBRAR cambiar nombre
- Sintaxis: RENOMBRE clave nueva clave
- Función: Cambiar el nombre de la clave a nueva clave. Devuelve un error cuando la clave es la misma que la clave nueva o la clave no existe. Cuando ya existe una nueva clave, el comando RENAME sobrescribirá el valor anterior.
- Versiones disponibles: >= 1.0.0
- Valor de retorno: solicita Aceptar cuando el nombre se cambia correctamente y devuelve un error cuando falla.
# 12.tipo de TIPO
- Sintaxis: clave TIPO
- Función: Devuelve el tipo de valor almacenado en la clave.
- Versiones disponibles: >= 1.0.0
- valor de retorno:
ninguno (la clave no existe)
cadena (cadena)
lista (lista)
conjunto (colección)
zset (conjunto ordenado)
hash (tabla hash)

8.3 Tipo de cadena

1. Modelo de almacenamiento de memoria

2. Comandos de operación comunes

Orden
ilustrar
colocar
establecer una clave/valor
conseguir
Obtener el valor correspondiente según la clave.
mset
Establecer varios valores clave a la vez
conseguir
Obtenga el valor de varias claves a la vez
prepararse
Obtenga el valor de la clave original y establezca el nuevo valor al mismo tiempo
strlen
Obtener la longitud del valor almacenado en la clave correspondiente
adjuntar
Agregar contenido al valor correspondiente a la clave.
El índice getrange 0 comienza, -1 significa el final.
Interceptar el contenido de valor.
sietex
Establecer el período de validez (segundos) para que sobreviva una nueva clave
psetex
Establecer el período de validez de una clave (en milisegundos)
setnx
Existe no hace nada, no existe agregar
Operación atómica msetnx (no hacer nada mientras exista una)
Se pueden configurar varias claves al mismo tiempo; mientras exista una, no se guardará
diciembre
Realizar -1 operación de tipo numérico
decrby
Realizar una operación de resta basada en los datos proporcionados.
Incr
Realizar operación +1 de tipo numérico
incrby
Agregar operación basada en los datos proporcionados
flotador incrby
Únase a flotadores según los datos proporcionados

conjunto hola hola

obtener hola

mset nombre wuxinke sexo hombre 20 años

mget nombre edad sexo Hola

prepárate hola oo200506

nombre strlen

agregar nombre liyi

obtener nombre de rango 0 6

setex pp 20 TTV

psetex a 10000 2021-12-12

setnx y wuxinke

msetnx quién quién dónde cuándo

edad decreciente

decby 10 años

aumentar la edad

edad adulta 100

edad incrbyfloat 1.23235434434343443

8.4 Tipo de lista

La lista de listas es equivalente a la función de recopilación de listas en Java, los elementos están ordenados y son repetibles.

1. Modelo de almacenamiento de memoria

2. Instrucciones de funcionamiento comunes

Orden
ilustrar
empujar
Agregar un valor al encabezado de una lista de claves
lpushx
Igual que lpush, pero debes asegurarte de que la clave exista
empujar
Agregar un valor al final de una lista de claves
rpushx
Igual que rpush, pero debes asegurarte de que la clave exista
pop
Devuelve y elimina el primer elemento a la izquierda de la lista.
pop
Devuelve y elimina el primer elemento de la derecha de la lista.
rango
Obtenga los elementos en un determinado rango de subíndices, comenzando con el índice 0 y terminando en -1
cortina
Obtener el número de elementos de la lista
colocar
Establecer el valor de un índice específico (el índice debe existir)
lindex
Obtener el elemento en una posición de índice especificada
irem
eliminar elementos duplicados
ltrim
Mantenga los elementos en un rango específico de la lista y elimine los demás
lentejado
Insertar un nuevo elemento antes y después de un elemento

lpush arr zhangsan zhaosi

lpushx arr wangwu

rpush arr zhaoliu

rpushx arr qianqi

arreglo lpop

rpop arr

rango de arreglo 0 -1

arreglo de cortina

lset arr 0 wuyifan

lindex arreglo 2

lrem arr 2 zhangsan

ltrim arr 0 1

linsert arr after wuyifan liuyifei

linsert arr before zhaoliu wujing

8.5 Set类型

特点: Set类型 Set集合 元素无序 不可以重复

1.内存存储模型

2.常用命令

命令
说明
sadd
为集合添加元素
smembers
显示集合中所有元素 无序
scard
返回集合中元素的个数
spop
随机返回一个元素 并将元素在集合中删除
smove
从一个集合中向另一个集合移动元素 必须是同一种类型
srem
从集合中删除一个元素
sismember
判断一个集合中是否含有这个元素 ,0:不包含,1:包含
srandmember
随机返回元素
sdiff
去掉第一个集合中和另一个集合含有的相同元
sinter
求交集
sunion
求和集

sadd sets wuyifan

smembers sets

scard sets

spop sets

smove sets sets2 qianqi

srem sets liuyifei

sismember sets wangwu

srandmember sets2

sdiff sets sets2

sinter sets sets2

sunion sets sets2

8.6 ZSet类型

特点: 可排序的set集合 排序 不可重复
ZSET 官方 可排序SET sortSet

1.内存模型

2.常用命令

命令
说明
zadd
添加一个有序集合元素
zcard
返回集合的元素个数
zrange 升序 zrevrange 降序
返回一个范围内的元素,起始索引0,末尾-1
zrangebyscore
按照分数查找一个范围内的元素
zrank
返回排名,0是第一
zrevrank
倒序排名
zscore
显示某一个元素的分数
zrem
移除某一个元素
zincrby
给某个特定元素加分

zadd zsets1 8 xiaoming 2 xiaohei

zcard zsets1

zrange zsets1 0 -1

zrevrange zsets1 0 -1

zrangebyscore zsets1 2 10

zrank zsets1 xiaohei

zrevrank zsets1 xiaohei

zscore zsets1 xiaoming

zrem zsets1 xiaoming

zincrby zsets1 10 xiaohei

8.7 hash类型

特点: value 是一个map结构 存在key value key 无序的

1.内存模型

2.常用命令

命令
说明
hset
设置一个key/value对
hget
获得一个key对应的value
hgetall
获得所有的key/value对
hdel
删除某一个key/value对
hexists
判断一个key是否存在,0:不存在,1:存在
hkeys
获得所有的key
hvals
获得所有的value
hmset
设置多个key/value
hmget
获得多个key的value
hsetnx
设置一个不存在的key的值
hincrby
为value进行加法运算
hincrbyfloat
为value加入浮点值
hset hsets1 oo1 zhangsan oo2 wangwu oo3 wuyifan
hget hsets1 oo2
hgetall hsets1
hdel hsets1 oo3
hexists hsets1 oo2
hkeys hsets1
hvals hsets1
hmset hsets1 003 tansongyun oo4 maobuyi
hmget hsets1 oo2 oo4
hsetnx hsets1 oo5 liyi
hincrby hsets1 oo6 5
hincrbyfloat hsets1 oo7 2.323652362323523262223323
8.8Redis可视化工具安装和连接
下载redis可视化工具,然后安装
修改配置文件 redis.conf
修改为 0.0.0.0
然后加载配置文件redis

9. 持久化机制

client redis[内存] -----> 内存数据- 数据持久化-->磁盘
Redis官方提供了两种不同的持久化方法来将数据存储到硬盘里面分别是:
  • 快照(Snapshot)
  • AOF (Append Only File) 只追加日志文件

9.1 快照(Snapshot)

1. 特点

这种方式可以将某一时刻的所有数据都写入硬盘中,当然这也是 redis的默认开启持久化方式 ,保存的文件是以.rdb形式结尾的文件因此这种方式也称之为RDB方式。

2.快照生成方式

  • 客户端方式: BGSAVE 和 SAVE指令
  • 服务器配置自动触发
# 1.客户端方式之BGSAVE
- a.客户端可以使用BGSAVE命令来创建一个快照,当接收到客户端的BGSAVE命令时,redis会调用fork¹来创建一个子进程,然后子进程负责将快照写入磁盘中,而父进程则继续处理命令请求。
`名词解释: fork当一个进程创建子进程的时候,底层的操作系统会创建该进程的一个副本,在类unix系统中创建子进程的操作会进行优化:在刚开始的时候,父子进程共享相同内存,直到父进程或子进程对内存进行了写之后,对被写入的内存的共享才会结束服务`
# 2.客户端方式之SAVE
- b.客户端还可以使用SAVE命令来创建一个快照,接收到SAVE命令的redis服务器在快照创建完毕之前将不再响应任何其他的命令
  • 注意: SAVE命令并不常用,使用SAVE命令在快照创建完毕之前,redis处于阻塞状态,无法对外服务
# 3.服务器配置方式之满足配置自动触发
- 如果用户在redis.conf中设置了save配置选项,redis会在save选项条件满足之后自动触发一次BGSAVE命令,如果设置多个save配置选项,当任意一个save配置选项条件满足,redis也会触发一次BGSAVE命令
# 4.服务器接收客户端shutdown指令
- 当redis通过shutdown指令接收到关闭服务器的请求时,会执行一个save命令,阻塞所有的客户端,不再执行客户端执行发送的任何命令,并且在save命令执行完毕之后关闭服务器

3.配置生成快照名称和位置

#1.修改生成快照名称
- dbfilename dump.rdb
# 2.修改生成位置
- dir ./

9.2 AOF 只追加日志文件

1.特点

这种方式可以将所有客户端执行的写命令记录到日志文件中,AOF持久化会将被执行的写命令写到AOF的文件末尾,以此来记录数据发生的变化,因此只要redis从头到尾执行一次AOF文件所包含的所有写命令,就可以恢复AOF文件的记录的数据集.

2.开启AOF持久化

在redis的默认配置中AOF持久化机制是没有开启的,需要在配置中开启
# 1.开启AOF持久化
- a.修改 appendonly yes 开启持久化
- b.修改 appendfilename "appendonly.aof" 指定生成文件名称

3.日志追加频率

# 1.always 【谨慎使用】
- 说明: 每个redis写命令都要同步写入硬盘,严重降低redis速度
- 解释: 如果用户使用了always选项,那么每个redis写命令都会被写入硬盘,从而将发生系统崩溃时出现的数据丢失减到最少;遗憾的是,因为这种同步策略需要对硬盘进行大量的写入操作,所以redis处理命令的速度会受到硬盘性能的限制;
- 注意: 转盘式硬盘在这种频率下200左右个命令/s ; 固态硬盘(SSD) 几百万个命令/s;
- 警告: 使用SSD用户请谨慎使用always选项,这种模式不断写入少量数据的做法有可能会引发严重的写入放大问题,导致将固态硬盘的寿命从原来的几年降低为几个月。
# 2.everysec 【推荐】
- 说明: 每秒执行一次同步显式的将多个写命令同步到磁盘
- 解释: 为了兼顾数据安全和写入性能,用户可以考虑使用everysec选项,让redis每秒一次的频率对AOF文件进行同步;redis每秒同步一次AOF文件时性能和不使用任何持久化特性时的性能相差无几,而通过每秒同步一次AOF文件,redis可以保证,即使系统崩溃,用户最多丢失一秒之内产生的数据。
# 3.no 【不推荐】
- 说明: 由操作系统决定何时同步
- 解释:最后使用no选项,将完全有操作系统决定什么时候同步AOF日志文件,这个选项不会对redis性能带来影响但是系统崩溃时,会丢失不定数量的数据,另外如果用户硬盘处理写入操作不够快的话,当缓冲区被等待写入硬盘数据填满时,redis会处于阻塞状态,并导致redis的处理命令请求的速度变慢。

4.修改同步频率

# 1.修改日志同步频率
- 修改appendfsync everysec|always|no 指定

9.3 AOF文件的重写

1. AOF带来的问题

AOF的方式也同时带来了另一个问题。持久化文件会变的越来越大。例如我们调用incr test命令100次,文件中必须保存全部的100条命令,其实有99条都是多余的。因为要恢复数据库的状态其实文件中保存一条set test 100就够了。为了压缩aof的持久化文件Redis提供了AOF重写(ReWriter)机制。

2. AOF重写

用来在一定程度上减小AOF文件的体积

3. 触发重写方式

# 1.客户端方式触发重写
- 执行BGREWRITEAOF命令 不会阻塞redis的服务
# 2.服务器配置方式自动触发
- 配置redis.conf中的auto-aof-rewrite-percentage选项 参加下图↓↓↓
- 如果设置auto-aof-rewrite-percentage值为100和auto-aof-rewrite-min-size 64mb,并且启用的AOF持久化时,那么当AOF文件体积大于64M,并且AOF文件的体积比上一次重写之后体积大了至少一倍(100%)时,会自动触发,如果重写过于频繁,用户可以考虑将auto-aof-rewrite-percentage设置为更大

4. 重写原理

注意:重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,替换原有的文件这点和快照有点类似。
# 重写流程
- 1. redis调用fork ,现在有父子两个进程 子进程根据内存中的数据库快照,往临时文件中写入重建数据库状态的命令
- 2. 父进程继续处理client请求,除了把写命令写入到原来的aof文件中。同时把收到的写命令缓存起来。这样就能保证如果子进程重写失败的话并不会出问题。
- 3. 当子进程把快照内容写入已命令方式写到临时文件中后,子进程发信号通知父进程。然后父进程把缓存的写命令也写入到临时文件。
- 4. 现在父进程可以使用临时文件替换老的aof文件,并重命名,后面收到的写命令也开始往新的aof文件中追加。

9.4 持久化总结

两种持久化方案既可以同时使用(aof),又可以单独使用,在某种情况下也可以都不使用,具体使用那种持久化方案取决于用户的数据和应用决定。
无论使用AOF还是快照机制持久化,将数据持久化到硬盘都是有必要的,除了持久化外,用户还应该对持久化的文件进行备份(最好备份在多个不同地方)。

10. java操作Redis

10.1 环境准备

1. 引入依赖

<!--引入jedis连接依赖-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>

2.创建jedis对象

public static void main(String[] args) {
//1.创建jedis对象
Jedis jedis = new Jedis("192.168.40.4", 6379);//1.redis服务必须关闭防火墙 2.redis服务必须开启远程连接
jedis.select(0);//选择操作的库默认0号库
//2.执行相关操作
//....
//3.释放资源
jedis.close();
}

10.2 操作key相关API

private Jedis jedis;
@Before
public void before(){
this.jedis = new Jedis("192.168.202.205", 7000);
}
@After
public void after(){
jedis.close();
}
//测试key相关
@Test
public void testKeys(){
//删除一个key
jedis.del("name");
//删除多个key
jedis.del("name","age");
//判断一个key是否存在exits
Boolean name = jedis.exists("name");
System.out.println(name);
//设置一个key超时时间 expire pexpire
Long age = jedis.expire("age", 100);
System.out.println(age);
//获取一个key超时时间 ttl
Long age1 = jedis.ttl("newage");
System.out.println(age1);
//随机获取一个key
String s = jedis.randomKey();
//修改key名称
jedis.rename("age","newage");
//查看可以对应值的类型
String name1 = jedis.type("name");
System.out.println(name1);
String maps = jedis.type("maps");
System.out.println(maps);
}
@Test
public void testKey(){
    //查询所有的key
    //Set<String> keys = jedis.keys("*");
    //删除key
    //Long name = jedis.del("name");
    //检查给定的key是否存在
    //Boolean name = jedis.exists("name");
    //为key设置生存时间,当key过期自动删除,设置时间为秒
    //Long who = jedis.expire("who", 1000);
    //查询符合条件的所有key
    //Set<String> keys1 = jedis.keys("w*");
    //移动key到指定数据库
    //Long age = jedis.move("age", 1);
    //设置key的存活时间,过期自动删除,设置时间为毫秒
    //Long oo = jedis.pexpireAt("oo", 10000);
    //查看key的剩余生存时间,时间为秒
    //Long who = jedis.ttl("who");
    //查看key的剩余生存时间,时间为毫秒
    //Long who = jedis.pttl("who");
    //从当前数据库中随机返回一个key,不删除
    //String s = jedis.randomKey();
    //修改key的名称
    //String rename = jedis.rename("when", "hh");
    //返回key存储值得类型
    //String arr = jedis.type("arr");
}

10.3操作String相关API

//测试String相关
@Test
public void testString(){
//set
jedis.set("name","小陈");
//get
String s = jedis.get("name");
System.out.println(s);
//mset
jedis.mset("content","好人","address","海淀区");
//mget
List<String> mget = jedis.mget("name", "content", "address");
mget.forEach(v-> System.out.println("v = " + v));
//getset
String set = jedis.getSet("name", "小明");
System.out.println(set);
//............
}
@Test
public void testString(){
    //设置一个key或者给指定的key设置值value
    //String set = jedis.set("wuxinke", "吴帅");
    //根据key获取value
    //String wuxinke = jedis.get("wuxinke");
    //一次设置多个key
    //String mset = jedis.mset("hao", "好好","weixin","OO200506");
    //一次获取多个key的value
    //List<String> mget = jedis.mget( "wuxinke","sex", "weixin");
    //获得key原始的值同时设置新的值
    //String set = jedis.getSet("wuxinke", "吴帅");
    //获取key存储的value值的长度
    //Long weixin = jedis.strlen("weixin");
    //给key追加能容
    //Long weixin = jedis.append("weixin", "0000");
    //截取key的value值
    //String weixin = jedis.getrange("weixin", 2, -1);
    //设置一个key存活的有效期,时间为秒
    //String setex = jedis.setex("hh", 60, "xx");
    //设置一个key存活的有效期,时间为毫秒
    //String hao = jedis.psetex("hao", 30000,"ninhao");
    //key存在不做任何操作,不存在添加
    //Long setnx = jedis.setnx("liyi", "李艺");
    //可以同时设置多个key,只要有一个存在都不保存
    //Long msetnx = jedis.msetnx("ww", "123", "aa", "456", "ee", "789");
    //对数值类型进行-1操作
    //Long aa = jedis.decr("aa");
    //根据提供的数据进行减法操作
    //Long aa = jedis.decrBy("aa", 10);
    //对数值类型+1操作
    //Long aa = jedis.incr("aa");
    //根据提供的数据进行加法操作
    //Long aa = jedis.incrBy("aa", 100);
    //根据提供的数据加上浮点数
    //Double aa = jedis.incrByFloat("aa", 10.99);
}

10.4操作List相关API

//测试List相关
@Test
public void testList(){
//lpush
jedis.lpush("names1","张三","王五","赵柳","win7");
//rpush
jedis.rpush("names1","xiaomingming");
//lrange
List<String> names1 = jedis.lrange("names1", 0, -1);
names1.forEach(name-> System.out.println("name = " + name));
//lpop rpop
String names11 = jedis.lpop("names1");
System.out.println(names11);
//llen
jedis.linsert("lists", BinaryClient.LIST_POSITION.BEFORE,"xiaohei","xiaobai");
//........
}
@Test
public void testList(){
    //将值加入到key列表头部
    //Long lpush = jedis.lpush("arr", "liyi", "wuxinke");
    //将值加入到key列表头部,但是必须保证key存在
    //Long lpushx = jedis.lpushx("arr", "zhangziyi", "zhangyixing");
    //将值添加到key列表末尾
    //Long rpush = jedis.rpush("arr", "yiyi");
    //将值添加到key列表末尾,但必须保证key存在
    //Long rpushx = jedis.rpushx("arr", "ziyi", "zirui");
    //返回和移除列表左边的第一个元素
    //String arr = jedis.lpop("arr");
    //返回和移除列表右边的第一个元素
    //String arr = jedis.rpop("arr");
    //获取某个key,下标区间的元素,起始索引0,结束-1
    //List<String> arr = jedis.lrange("arr", 0, -1);
    //获取列表元素个数
    //Long arr = jedis.llen("arr");
    //设置某一个指定索引的值,索引必须存在
    //String arr = jedis.lset("arr", 2, "123");
    //获取某一个指定索引位置的元素
    //String arr = jedis.lindex("arr", 2);
    //删除重复元素
    //Long lrem = jedis.lrem("arr", 1, "yiyi");
    //保存列表中指定区间的元素其他都删除
    //String arr = jedis.ltrim("arr", 2, 4);
    //在某一个元素之前或者之后插入元素
    //Long linsert = jedis.linsert("arr", BinaryClient.LIST_POSITION.BEFORE,"liuyifei","xingke");
}

10.5操作Set的相关API        

//测试SET相关
@Test
public void testSet(){
//sadd
jedis.sadd("names","zhangsan","lisi");
//smembers
jedis.smembers("names");
//sismember
jedis.sismember("names","xiaochen");
//...
}
@Test
public void testSet(){
    //为集合添加元素
    //Long sadd = jedis.sadd("sets", "zhaoliu", "wangwu");
    //显示集合中的所有元素,无序
    //Set<String> sets = jedis.smembers("sets");
    //返回集合中得个数
    //Long scard = jedis.scard("sets");
    //随机返回一个元素,并删除该元素
    //String sets = jedis.spop("sets");
    //从一个集合中向另一个集合中移动元素,必须是同一种类型
    //Long smove = jedis.smove("sets", "sets2", "zhaoxinbing");
    //从集合中删除一个元素
    //Long srem = jedis.srem("sets", "qianqi");
    //判断一个集合中是否存在这个元素
    //Boolean sismember = jedis.sismember("sets", "zhangsan");
    //随机返回一个元素
    //String sets = jedis.srandmember("sets");
    //去掉第一个集合中和其他集合含有的相同元素,不删除
    //Set<String> sdiff = jedis.sdiff("sets", "sets2");
    //求交集
    //Set<String> sets = jedis.sinter("sets","sets2");
    //求和集
    //Set<String> sets = jedis.sunion("sets","sets2");
}

10.6 操作ZSet相关API

//测试ZSET相关
@Test
public void testZset(){
//zadd
jedis.zadd("names",10,"张三");
//zrange
jedis.zrange("names",0,-1);
//zcard
jedis.zcard("names");
//zrangeByScore
jedis.zrangeByScore("names","0","100",0,5);
//..
}
@Test
public void testZset(){
    //添加一个有序集合元素
    //Long zadd = jedis.zadd("zsets1", 86.3, "zhangsan");
    //返回集合的元素个数
    //Long zsets1 = jedis.zcard("zsets1");
    //按照分数查找一个范围内的元素
    //Set<String> zsets1 = jedis.zrangeByScore("zsets1", 80, 100);
    //返回排名
    //Long zsets1 = jedis.zrank("zsets1","zhangsan");
    //倒序排名
    //Long zsets1 = jedis.zrevrank("zsets1", "xiaohei");
    //显示某一个元素的分数
    //Double zscore = jedis.zscore("zsets1", "xiaohei");
    //移除某一个元素
    //Long zrem = jedis.zrem("zsets1", "xiaohei");
    //给某一个特定元素加分
    //Double zincrby = jedis.zincrby("zsets1", 10, "zahngsan");
}

10.7 操作Hash相关API

//测试HASH相关
@Test
public void testHash(){
//hset
jedis.hset("maps","name","zhangsan");
//hget
jedis.hget("maps","name");
//hgetall
jedis.hgetAll("mps");
//hkeys
jedis.hkeys("maps");
//hvals
jedis.hvals("maps");
//....
}
@Test
public void testHash(){
    //设置一个key/value对
    //Long hset = jedis.hset("hsets1", "yijia", "wuxinke");
    //获得一个key对应的value
    //String hget = jedis.hget("hsets1", "yijia");
    //获得所有的key/value对
    //Map<String, String> hsets1 = jedis.hgetAll("hsets1");
    //删除某一个key/value对
    //Long hdel = jedis.hdel("hsets1", "oo6");
    //判断一个key是否存在
    //Boolean hexists = jedis.hexists("hsets1", "oo4");
    //获得所有的key
    //Set<String> hsets1 = jedis.hkeys("hsets1");
    //获得所有的value
    //List<String> hsets1 = jedis.hvals("hsets1");
    //设置多个key/value 对
    //HashMap<String, String> map = new HashMap<>();
    //map.put("yijia","liyi");
    //map.put("996","nono");
    //String hsets1 = jedis.hmset("hsets1", map);
    //获得多个key的value
    //List<String> hmget = jedis.hmget("hsets1", "oo5", "oo7", "yijia");
    //给一个不存在的key设置值
    //Long hsetnx = jedis.hsetnx("hsets1", "love", "liyi");
    //对value进行加法运算
    //Long aLong = jedis.hincrBy("hsets1", "yi1", 5);
    //对value加入浮点值
    //Double aDouble = jedis.hincrByFloat("hsets1", "yi2", 9.99);
}

11.SpringBoot整合Redis

Spring Boot Data(数据) Redis 中提供了 RedisTemplate和StringRedisTemplate ,其中StringRedisTemplate是RedisTemplate的子类,两个方法基本一致,不同之处主要体现在操作的数据类型不同, RedisTemplate中的两个泛型都是Object,意味着存储的key和value都可以是一个对象,而StringRedisTemplate的两个泛型都是String,意味着StringRedisTemplate的key和value都只能是字符串。
注意: 使用RedisTemplate默认是将对象序列化到Redis中,所以放入的对象必须实现对象序列化接口

11.1 环境准备

1.引入依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.5.3</version>
</dependency>

2.配置application.propertie

spring.redis.host=localhost
spring.redis.port=6379
spring.redis.database=0

11.2 使用StringRedisTemplate和RedisTemplate

StringRedisTemplate操作
@Autowired
private StringRedisTemplate stringRedisTemplate;
//对key进行操作
@Test
public void testKey(){
    //查询条件查询key    *:匹配多个字母  ?:匹配一个字母   []:匹配括号里面任意一个字母
    //Set<String> keys = stringRedisTemplate.keys("*");//匹配所有key
    //Set<String> keys = stringRedisTemplate.keys("w*");//匹配w开头的所有key
    //Set<String> keys = stringRedisTemplate.keys("a[ae]");//匹配a开头,第二个字母a或者e
    //Set<String> keys = stringRedisTemplate.keys("a?");//匹配a开头两个字母的key(第二个字母任意)
    //删除指定的key
    //Boolean ae = stringRedisTemplate.delete("ae");//删除指定的一个key,返回真假,true:删除成功,false:删除失败
    //ArrayList<String> list = new ArrayList<>();
    //list.add("where");
    //list.add("ww");
    //list.add("aa");
    //Long delete = stringRedisTemplate.delete(list);//删除指定的多个key,返回删除个数
    //检查指定的key是否存在
    //Boolean sex = stringRedisTemplate.hasKey("sex");//返回真假,true:存在,false:不存在
    //给指定的key设置生存时间,过期自动删除,时间单位可以是 天,小时,分钟,秒,毫秒
    //Boolean ee = stringRedisTemplate.expire("Hello", Duration.ofSeconds(50));//返回真假,true:设置成功,false:设置失败
    //移动key到其他数据库中,redis有16个数据库,编号为0-15
    //Boolean oo = stringRedisTemplate.move("oo", 1);//返回真假,true:移动成功,false:移动失败
    //获取指定key的类型
    //DataType sex = stringRedisTemplate.type("sex");//返回DataType对象,DataType对象里面有对应的数据类型解释
    //获取指定key的存活的剩余时间单位秒
    //Long sex = stringRedisTemplate.getExpire("Hello");//返回存活的剩余时间
    //在当前数据库随机返回一个key,不删除
    //String s = stringRedisTemplate.randomKey();
    //修改key的名称
    //stringRedisTemplate.rename("liyi","home");
}
//对String进行操作
@Test
public void testString(){
    //设置一个key
    //stringRedisTemplate.opsForValue().set("we","wuxinke and liyi");
    //根据key获取对应的value
    //String we = stringRedisTemplate.opsForValue().get("we");
    //一次设置多个key和value
    //HashMap<String, String> map = new HashMap<>();
    //map.put("name1","zhangsan");
    //map.put("name2","zhaosi");
    //map.put("name3","wangwu");
    //stringRedisTemplate.opsForValue().multiSet(map);
    //一次获取多个key的value
    //Collection<String> collection = new ArrayList<>();
    //collection.add("name1");
    //collection.add("name2");
    //collection.add("name3");
    //List<String> list = stringRedisTemplate.opsForValue().multiGet(collection);
    //根据key获取原始的value,同时设置新的value
    //String andSet = stringRedisTemplate.opsForValue().getAndSet("we", "Wuxinke Love Liyi");
    //根据key获取对应value的长度
    //Long we = stringRedisTemplate.opsForValue().size("we");  //返回value的长度,空格也算
    //根据key给对应的value追加内容
    //Integer we = stringRedisTemplate.opsForValue().append("we", " 1314");//返回追加之后的value长度,空格也算
    //截取value的内容,起始索引是0,-1表示末尾
    //String we = stringRedisTemplate.opsForValue().get("we", 0, -1);
    //设置一个新key存活的有效期,过期自动删除,时间单位可以是 天,小时,分钟,秒,毫秒
    //stringRedisTemplate.opsForValue().set("#001","井001",Duration.ofSeconds(60));
    //stringRedisTemplate.opsForValue().set("#002","井002",60*10, TimeUnit.SECONDS);
    //判断key是否存在,存在不做任何操作,存在做添加操作
    //Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent("Liyi", "宁宁");//返回真假,true:不存在,false:不存在
    //同时添加多个key,只要有一个存在都不做添加
    //HashMap<String, String> map = new HashMap<>();
    //map.put("keys4","value4");
    //map.put("keys5","value5");
    //map.put("Liyi","ll");
    //Boolean aBoolean1 = stringRedisTemplate.opsForValue().multiSetIfAbsent(map);//返回真假,true:添加成功,false:添加失败
    //根据key对对应的value进行-1操作,value是数字必须是类型
    //Long age = stringRedisTemplate.opsForValue().decrement("age");//返回操作后的数值
    //根据key对对应的value进行减法操作,value是数字必须是类型
    //Long age1 = stringRedisTemplate.opsForValue().decrement("age", 2);//返回操作后的数值
    //根据key对对应的value进行+1操作,value是数字必须是类型
    //Long age = stringRedisTemplate.opsForValue().increment("age");//返回操作后的数值
    //根据key对对应的value进行加法操作,value是数字必须是类型
    //Long age = stringRedisTemplate.opsForValue().increment("age", 5);//返回操作后的数值
    //根据key对对应的value进行浮点数的加法操作,value是数字必须是类型
    //Double age = stringRedisTemplate.opsForValue().increment("age", 5.5);//返回操作后的数值
}
//对List集合进行操作
@Test
public void testList(){
    //将某一个数据加入到某个集合的头部,key不存在不会报错,会创建key类型为list
    //Long aLong = stringRedisTemplate.opsForList().leftPush("a1", "name1");//返回集合中key的个数
    //将某一个数据加入到某个集合的头部,key不存在,不会创建key
    //Long aLong = stringRedisTemplate.opsForList().leftPushIfPresent("aaaaaa", "name3");//返回集合中key的个数
    //将某一个数据加入到某个集合的末尾,key不存在不会报错,会创建key类型为list
    //Long aLong1 = stringRedisTemplate.opsForList().rightPush("a", "name4");//返回集合中key的个数
    //将某一个数据加入到某个集合的末尾,key不存在,不会创建key
    //Long aLong1 = stringRedisTemplate.opsForList().rightPushIfPresent("asss", "name4");//返回集合中key的个数
    //返回并移除列表左边的第一个元素
    //String arr = stringRedisTemplate.opsForList().leftPop("arr");
    //返回并移除列表右边的第一个元素
    //String arr = stringRedisTemplate.opsForList().rightPop("arr");
    //根据key获取某一个下标区间内的元素,起始索引:0,末尾:1
    //List<String> arr = stringRedisTemplate.opsForList().range("arr", 2, -1);
    //获取列表内元素个数
    //Long arr1 = stringRedisTemplate.opsForList().size("arr");
    //给某个指定索引位置设置值,如果该索引有值就覆盖,索引必须存在
    //stringRedisTemplate.opsForList().set("arr",2,"zhangsan");
    //获取指定索引位置的元素
    //String arr = stringRedisTemplate.opsForList().index("arr", 2);
    //删除重复元素,key:key,count:删除个数,value:元素名称
    //Long remove = stringRedisTemplate.opsForList().remove("arr", 2, "name1");
    //保留列表中特定区间内的元素,其他都删除
    //stringRedisTemplate.opsForList().trim("arr",2,-1);
}
//对set集合进行操作
@Test
public void testSet(){
    //添加元素
    //Long add = stringRedisTemplate.opsForSet().add("sets", "李四");//返回添加个数,1:添加一条,0:没有添加进去
    //显示集合中所有元素,无序
    //Set<String> sets = stringRedisTemplate.opsForSet().members("sets");
    //返回集合中元素个数
    //Long size = stringRedisTemplate.opsForSet().size("sets");
    //随机返回一个元素,并将该元素删除
    //String sets = stringRedisTemplate.opsForSet().pop("sets");
    //从一个集合向另一个集合中移动元素,必须是同一种类型的key
    //Boolean move = stringRedisTemplate.opsForSet().move("sets", "张三", "sets2");//返回真假,true:成功,false:失败
    //从指定的key集合中删除一个或多个元素
    //Long remove = stringRedisTemplate.opsForSet().remove("sets", "6", "李四");//返回删除的个数
    //在指定的key中判断一个集合中是否包含指定元素
    //Boolean member = stringRedisTemplate.opsForSet().isMember("sets", "5");//返回真假,true:存在,false:不存在
    //随机返回一个元素,不删除
    //String sets = stringRedisTemplate.opsForSet().randomMember("sets");
    //获取两个集合或多个集合没有重复的元素,不做删除
    //Set<String> difference = stringRedisTemplate.opsForSet().difference("sets", "sets2");//返回去重后的集合
    //获取两个集合或多个集合中重复的元素,不做删除
    //Set<String> intersect = stringRedisTemplate.opsForSet().intersect("sets", "sets2");//返回交集后的集合
    //获取两个集合或多个集合中所有的元素,不做删除
    //Set<String> union = stringRedisTemplate.opsForSet().union("sets", "sets2");//返回合集后的集合
}
//对ZSet集合进行操作
@Test
public void testZSet(){
    //向指定的集合中添加一个或多个元素
    //Boolean add = stringRedisTemplate.opsForZSet().add("zsets1", "张三", 66.5);
    //ZSetOperations.TypedTuple<String> typedTuple1 = new DefaultTypedTuple<String>("吴新科",100.0);
    //ZSetOperations.TypedTuple<String> typedTuple2 = new DefaultTypedTuple<String>("李艺",99.9);
    //ZSetOperations.TypedTuple<String> typedTuple3 = new DefaultTypedTuple<String>("赵四",95.6);
    //HashSet<ZSetOperations.TypedTuple<String>> hashSet = new HashSet<>();
    //hashSet.add(typedTuple1);
    //hashSet.add(typedTuple2);
    //hashSet.add(typedTuple3);
    //Long zsets1 = stringRedisTemplate.opsForZSet().add("zsets1", hashSet);
    //返回集合中元素个数
    //Long zsets1 = stringRedisTemplate.opsForZSet().size("zsets1");
    //返回指定范围内的元素,升序,起始索引:0,末尾:-1
    //Set<String> zsets11 = stringRedisTemplate.opsForZSet().range("zsets1", 0, -1);
    //返回指定范围内的元素,降序,起始索引:0,末尾:-1
    //Set<String> zsets11 = stringRedisTemplate.opsForZSet().reverseRange("zsets1",0,-1);
    //按照分数查找一个范围内的元素
    //Set<String> zsets1 = stringRedisTemplate.opsForZSet().rangeByScore("zsets1",90.0,100.0);
    //返回指定元素的排名,排名按照添加顺序排名,第一名为0
    //Long zsets1 = stringRedisTemplate.opsForZSet().rank("zsets1","李艺");
    //返回指定元素的倒序排名,排名按照添加顺序排名,第一名为0
    //Long aLong = stringRedisTemplate.opsForZSet().reverseRank("zsets1", "吴新科");
    //显示某一个元素的分数
    //Double score = stringRedisTemplate.opsForZSet().score("zsets1", "吴新科");
    //移除某一个元素
    //Long remove = stringRedisTemplate.opsForZSet().remove("zsets1", "zahngsan");
    //给某个特定元素加分
    //Double aDouble = stringRedisTemplate.opsForZSet().incrementScore("zsets1", "张三", 5.5);//返回加分后的分数
}
//对hash集合进行操作
@Test
public void testHash(){
    //添加一个或多个元素
    //stringRedisTemplate.opsForHash().put("map","吴新科","196");
    //HashMap<String, String> map = new HashMap<>();
    //map.put("李艺","199");
    //map.put("吴旭","182");
    //map.put("李浩","112");
    //stringRedisTemplate.opsForHash().putAll("map",map);
    //获得key对应的value
    //Object o = stringRedisTemplate.opsForHash().get("map", "吴新科");
    //获得所有的key/value对
    //Map<Object, Object> map = stringRedisTemplate.opsForHash().entries("map");
    //Map集合的循环遍历采用lambda表达式方式
    //map.entrySet().forEach(m-> System.out.println(m.getKey()+"--"+m.getValue()));
    //删除指定的一个key或多个key
    //Long delete = stringRedisTemplate.opsForHash().delete("map", "李浩");//返回成功删除的个数
    //Long delete = stringRedisTemplate.opsForHash().delete("map", "李浩","吴旭");//返回成功删除的个数
    //判断一个key是否存在
    //Boolean aBoolean = stringRedisTemplate.opsForHash().hasKey("map", "李艺");//返回真假,true:存在,false:不存在
    //获得所有的key
    //Set<Object> map = stringRedisTemplate.opsForHash().keys("map");
    //获得所有的value
    //List<Object> map = stringRedisTemplate.opsForHash().values("map");
    //获得多个key的value
    //ArrayList<Object> list = new ArrayList<>();
    //list.add("吴新科");
    //list.add("李艺");
    //List<Object> map = stringRedisTemplate.opsForHash().multiGet("map", list);
    //判断key是否存在,存在不添加,不存在添加
    //Boolean aBoolean = stringRedisTemplate.opsForHash().putIfAbsent("map", "浩浩", "126");//返回真假,true:不存在添加,false:存在不添加
    //对指定的value进行加法运算,
    //Long increment = stringRedisTemplate.opsForHash().increment("map", "吴新科", 10);//反对会运算后的结果
    //Double increment1 = stringRedisTemplate.opsForHash().increment("map", "吴新科", 10.8);//反对会运算后的结果
}
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testRedisTemplate(){
    //redisTemplate的key使设置序列化策略,默认是JdkSerializationRedisSerializer策略,可以修改成StringRedisSerializer
    redisTemplate.setKeySerializer(new StringRedisSerializer());
    //redisTemplate的value使设置序列化策略,默认是JdkSerializationRedisSerializer策略,可以修改成StringRedisSerializer
    redisTemplate.setValueSerializer(new StringRedisSerializer());
    //redisTemplate的hash集合的key使设置序列化策略,默认是JdkSerializationRedisSerializer策略,可以修改成StringRedisSerializer
    redisTemplate.setHashKeySerializer(new StringRedisSerializer());
    //redisTemplate的hash集合的value使设置序列化策略,默认是JdkSerializationRedisSerializer策略,可以修改成StringRedisSerializer
    redisTemplate.setHashValueSerializer(new StringRedisSerializer());
}
@Autowired
private StringRedisTemplate stringRedisTemplate; //对字符串支持比较友好,不能存储对象
@Autowired
private RedisTemplate redisTemplate; //存储对象
@Test
public void testRedisTemplate(){
        System.out.println(redisTemplate);
        //设置redistemplate值使用对象序列化策略
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());//指定值使用对象序列化
        //redisTemplate.opsForValue().set("user",new User("21","小黑",23,new Date()));
        User user = (User) redisTemplate.opsForValue().get("user");
        System.out.println(user);
        // Set keys = redisTemplate.keys("*");
        // keys.forEach(key -> System.out.println(key));
        /*Object name = redisTemplate.opsForValue().get("name");
        System.out.println(name);*/
        //Object xiaohei = redisTemplate.opsForValue().get("xiaohei");
        //System.out.println(xiaohei);
        /*redisTemplate.opsForValue().set("name","xxxx");
        Object name = redisTemplate.opsForValue().get("name");
        System.out.println(name);*/        
        /*redisTemplate.opsForList().leftPushAll("lists","xxxx","1111");
        List lists = redisTemplate.opsForList().range("lists", 0, -1);
        lists.forEach(list-> System.out.println(list));*/
}
//key的绑定操作 如果日后对某一个key的操作及其频繁,可以将这个key绑定到对应redistemplate中,日后基于绑定操作都是操作这个key
//boundValueOps 用来对String值绑定key
//boundListOps 用来对List值绑定key
//boundSetOps 用来对Set值绑定key
//boundZsetOps 用来对Zset值绑定key
//boundHashOps 用来对Hash值绑定key
@Test
public void testBoundKey(){
        BoundValueOperations<String, String> nameValueOperations = stringRedisTemplate.boundValueOps("name");
        nameValueOperations.set("1");
        //yuew
        nameValueOperations.set("2");
        String s = nameValueOperations.get();
        System.out.println(s);
}
//hash相关操作 opsForHash
@Test
public void testHash(){
        stringRedisTemplate.opsForHash().put("maps","name","小黑");
        Object o = stringRedisTemplate.opsForHash().get("maps", "name");
        System.out.println(o);
}
//zset相关操作 opsForZSet
@Test
public void testZSet(){
        stringRedisTemplate.opsForZSet().add("zsets","小黑",10);
        Set<String> zsets = stringRedisTemplate.opsForZSet().range("zsets", 0, -1);
        zsets.forEach(value-> System.out.println(value));
}
//set相关操作 opsForSet
@Test
public void testSet(){
        stringRedisTemplate.opsForSet().add("sets","xiaosan","xiaosi","xiaowu");
        Set<String> sets = stringRedisTemplate.opsForSet().members("sets");
        sets.forEach(value-> System.out.println(value));
}
//list相关的操作opsForList
@Test
public void testList(){
        // stringRedisTemplate.opsForList().leftPushAll("lists","张三","李四","王五");
        List<String> lists = stringRedisTemplate.opsForList().range("lists", 0, -1);
        lists.forEach(key -> System.out.println(key));
}
//String相关的操作 opsForValue
@Test
public void testString(){
        //stringRedisTemplate.opsForValue().set("166","好同学");
        String s = stringRedisTemplate.opsForValue().get("166");
        System.out.println(s);
        Long size = stringRedisTemplate.opsForValue().size("166");
        System.out.println(size);
}
//key相关的操作
@Test
public void test(){
        Set<String> keys = stringRedisTemplate.keys("*");//查看所有key
        Boolean name = stringRedisTemplate.hasKey("name");//判断某个key是否存在
        stringRedisTemplate.delete("age");//根据指定key删除
        stringRedisTemplate.rename("","");//修改key的名称
        stringRedisTemplate.expire("key",10, TimeUnit.HOURS);
        //设置key超时时间 参数1:设置key名 参数2:时间 参数3:时间的单位
        stringRedisTemplate.move("",1);//移动key
}
11.3 Redis中分布式缓存
[1].MyBatis二级缓存
    注意:
            1.实体类实现序列化
            2.mapper.xml文件中添加<cache/>标签
application.properties文件配置
#启动服务端口
server.port=8088
#数据源
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#mysql数据库驱动
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#mysql数据库连接地址
spring.datasource.url=jdbc:mysql://localhost:3306/homework?characterEncoding=UTF-8
#mysql账号
spring.datasource.username=root
#mysql密码
spring.datasource.password=root
#指定xml的路径
mybatis.mapper-locations=classpath:mapper/*.xml
#指定起别名的路径
mybatis.type-aliases-package=com.oo.bean
#打印日志
logging.level.com.oo.dao=debug
[2.].Redis缓存
    注意:
            1.实体类实现序列化
            2.mapper.xml文件中添加<cache type="配置的Cache全路径"/>标签
配置的Cache类实现的Cache类( org.apache.ibatis.cache.Cache )
public class RedisCache implements Cache {
    //当前存入缓存的mapper的namespace
    private final String id;
    //构造方法
    public RedisCache(String id){
        this.id=id;
    }
    //返回cache唯一标识
    @Override
    public String getId() {
        return this.id;
    }
    //缓存放入值(会先从redis数据库查,查不到再去mysql数据库查,然后再缓存到redis数据库中)
    @Override
    public void putObject(Object o, Object o1) {
        getRedisTemplate().opsForHash().put(id.toString(),o.toString(),o1);
    }
    //缓存中获取值(redis中有缓存的数据,就从redis数据库中获取,不走mysql数据库)
    @Override
    public Object getObject(Object o) {
        return getRedisTemplate().opsForHash().get(id.toString(),o.toString());
    }
    @Override
    public Object removeObject(Object o) {
        return null;
    }
    //清除缓存(增删改会先清除redis数据库里缓存的数据)
    @Override
    public void clear() {
        getRedisTemplate().delete(id.toString());
    }
    //缓存数量
    @Override
    public int getSize() {
        return getRedisTemplate().opsForHash().size(id.toString()).intValue();
    }
    @Override
    public ReadWriteLock getReadWriteLock() {
        return null;
    }
    public RedisTemplate getRedisTemplate(){
        RedisTemplate redisTemplate = (RedisTemplate) RedisContextUtils.getBean("redisTemplate");
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        return redisTemplate;
    }
}
Spring工厂创建RedisTemplate
@Component
public class RedisContextUtils implements ApplicationContextAware {
    //保留下来工厂
    private  static ApplicationContext applicationContext;
    //将创建好工厂以参数形式传递给这个类
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }
    //提供在工厂中获取对象的方法
    public static Object getBean(String beanName){
        return applicationContext.getBean(beanName);
    }
}
缓存优化
有关联关系sql使用<cache-ref namespace="关联关系的dao全命名"></cache-ref>
StudentMapper.xml
UserMapper.xml
key的优化,使用MD5加密

12. Redis 主从复制

12.1 主从复制

主从复制架构仅仅用来解决数据的冗余备份,从节点仅仅用来同步数据
无法解决: 1.master节点出现故障的自动故障转移

12.2 主从复制架构图

12.3 搭建主从复制

# 1.准备3台机器并修改配置
- master
port 6379
bind 0.0.0.0
- slave1
port 6380
bind 0.0.0.0
slaveof masterip masterport
- slave2
port 6381
bind 0.0.0.0
slaveof masterip masterport
# 2.启动3台机器进行测试
- cd /usr/redis/bin
- ./redis-server /root/master/redis.conf
- ./redis-server /root/slave1/redis.conf
- ./redis-server /root/slave2/redis.conf

13. Redis哨兵机制

13.1 哨兵Sentinel机制

Sentinel(哨兵)是Redis 的高可用性解决方案:由一个或多个Sentinel 实例 组成的Sentinel 系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器。简单的说哨兵就是带有 自动故障转移功能的主从架构
无法解决: 1.单节点并发压力问题 2.单节点内存和磁盘物理上限

13.2 哨兵架构原理

13.3 搭建哨兵架构

# 1.在主节点上创建哨兵配置
- 在Master对应redis.conf同目录下新建sentinel.conf文件,名字绝对不能错;
# 2.配置哨兵,在sentinel.conf文件中填入内容:
- sentinel monitor 被监控数据库名字(自己起名字) ip port 1
# 3.启动哨兵模式进行测试
- redis-sentinel /root/sentinel/sentinel.conf
说明:这个后面的数字2,是指当有两个及以上的sentinel服务检测到master宕机,才会去执行主从切换的功能。

13.4 通过springboot操作哨兵

# redis sentinel 配置
# master书写是使用哨兵监听的那个名称
spring.redis.sentinel.master=mymaster
# 连接的不再是一个具体redis主机,书写的是多个哨兵节点
spring.redis.sentinel.nodes=192.168.202.206:26379
  • 注意:如果连接过程中出现如下错误:RedisConnectionException: DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are only accepted from the loopback interface. If you want to connect from external computers to Redis you may adopt one of the following solutions: 1) Just disable protected mode sending the command 'CONFIG SET protected-mode no' from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent. 2)
  • 解决方案:在哨兵的配置文件中加入bind 0.0.0.0 开启远程连接权限

14. Redis集群

14.1 集群

Redis在3.0后开始支持Cluster(模式)模式,目前redis的集群支持节点的自动发现,支持slave-master选举和容错,支持在线分片(sharding shard )等特性。reshard

14.2 集群架构图

14.3 集群细节

- 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
- 节点的fail是通过集群中超过半数的节点检测失效时才生效.
- 客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
- redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value

14.4 集群搭建

判断一个是集群中的节点是否可用,是集群中的所用主节点选举过程,如果半数以上的节点认为当前节点挂掉,那么当前节点就是挂掉了,所以搭建redis集群时建议节点数最好为奇数, 搭建集群至少需要三个主节点,三个从节点,至少需要6个节点
# 1.准备环境安装ruby以及redis集群依赖
- yum install -y ruby rubygems
- gem install redis-xxx.gem
执行 gem install redis-xxx.gem出现如下代码证明安装成功
Successfully installed redis-3.2.1
Parsing documentation for redis-3.2.1
Installing ri documentation for redis-3.2.1
1 gem installed
# 2.在一台机器创建7个目录
# 3.每个目录复制一份配置文件
[root@localhost ~]# cp redis-4.0.10/redis.conf 7000/
[root@localhost ~]# cp redis-4.0.10/redis.conf 7001/
[root@localhost ~]# cp redis-4.0.10/redis.conf 7002/
[root@localhost ~]# cp redis-4.0.10/redis.conf 7003/
[root@localhost ~]# cp redis-4.0.10/redis.conf 7004/
[root@localhost ~]# cp redis-4.0.10/redis.conf 7005/
[root@localhost ~]# cp redis-4.0.10/redis.conf 7006/
# 4.修改不同目录配置文件
- port 6379 .....                                                   //修改端口
- bind 0.0.0.0                                                    //开启远程连接
- cluster-enabled yes                                     //开启集群模式
- cluster-config-file nodes-port.conf         //集群节点配置文件
- cluster-node-timeout 5000                    //集群节点超时时间
- appendonly yes                                     //开启AOF持久化
-daemonize yes                                      //守护进程启动,启动之后不会占用一个窗口,在后台启动(不改也行)
# 5.指定不同目录配置文件启动七个节点
- [root@localhost bin]# ./redis-server /root/7000/redis.conf
- [root@localhost bin]# ./redis-server /root/7001/redis.conf
- [root@localhost bin]# ./redis-server /root/7002/redis.conf
- [root@localhost bin]# ./redis-server /root/7003/redis.conf
- [root@localhost bin]# ./redis-server /root/7004/redis.conf
- [root@localhost bin]# ./redis-server /root/7005/redis.conf
- [root@localhost bin]# ./redis-server /root/7006/redis.conf
# 6.查看进程
- [root@localhost bin]# ps aux|grep redis

1.创建集群

# 1.复制集群操作脚本到bin目录中
- [root@localhost bin]# cp /root/redis-4.0.10/src/redis-trib.rb .
# 2.创建集群
- ./redis-trib.rb create --replicas 1 192.168.202.205:7000 192.168.202.205:7001 192.168.202.205:7002 192.168.202.205:7003 192.168.202.205:7004 192.168.202.205:7005
# 3.集群创建成功出现如下提示

2.查看集群状态

# 1.查看集群状态 check [原始集群中任意节点] [无]
- ./redis-trib.rb check 192.168.202.205:7000
# 2.集群节点状态说明
- 主节点
主节点存在hash slots,且主节点的hash slots 没有交叉
主节点不能删除
一个主节点可以有多个从节点
主节点宕机时多个副本之间自动选举主节点
- 从节点
从节点没有hash slots
从节点可以删除
从节点不负责数据的写,只负责数据的同步

3.添加主节点

# 1.添加主节点 add-node [新加入节点] [原始集群中任意节点]
- ./redis-trib.rb add-node 192.168.1.158:7006 192.168.1.158:7005
- 注意:
1.该节点必须以集群模式启动
2.默认情况下该节点就是以master节点形式添加

4.添加从节点

# 1.添加从节点 add-node --slave [新加入节点] [集群中任意节点]
- ./redis-trib.rb add-node --slave 192.168.1.158:7006 192.168.1.158:7000
- 注意:
当添加副本节点时没有指定主节点,redis会随机给副本节点较少的主节点添加当前副本节点
# 2.为确定的master节点添加主节点 add-node --slave --master-id master节点id [新加入节点] [集群任意节点]
- ./redis-trib.rb add-node --slave --master-id 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 127.0.0.1:7006 127.0.0.1:7000

5.删除副本节点

# 1.删除节点 del-node [集群中任意节点] [删除节点id]
- ./redis-trib.rb del-node 127.0.0.1:7002 0ca3f102ecf0c888fc7a7ce43a13e9be9f6d3dd1
- 注意:
1.被删除的节点必须是从节点或没有被分配hash slots的节点

6.集群在线分片

# 1.在线分片 reshard [集群中任意节点] [无]
- ./redis-trib.rb reshard 192.168.1.158:7000

15.Redis实现分布式Session管理

15.1 管理机制

La gestión de sesiones de redis consiste en utilizar la solución de gestión de sesiones proporcionada por Spring para transferir una sesión de la aplicación a Redis para su almacenamiento, y todas las solicitudes de sesión en toda la aplicación irán a redis para obtener los datos de la sesión correspondientes.

15.2 Desarrollo de la gestión de sesiones

1. Introducir dependencias

<dependencia>
<groupId>org.springframework.session</groupId>
<artifactId>datos-de-sesión-de-primavera-redis</artifactId>
</dependencia>

2. Desarrollar la clase de configuración de gestión de sesiones.

@Configuración
@EnableRedisHttpSession
clase pública RedisSessionManager {
}

3. Simplemente empaca y prueba


¡Actualizado continuamente!

Supongo que te gusta

Origin blog.csdn.net/weixin_51689532/article/details/130686806
Recomendado
Clasificación