Учебное пособие по SpringBoot (14) | SpringBoot интегрирует Redis (наиболее полный во всей сети)
Учебное пособие по SpringBoot (14) | SpringBoot интегрирует Redis (наиболее полный во всей сети)

1. Введение в интеграцию Redis

Redis — это база данных nosql, которая очень часто используется при разработке Java. Данные хранятся в памяти в виде пар ключ-значение. Общие сценарии использования Redis включают кеширование, распределенные блокировки, последовательности с автоматическим приращением и т. д. Способ использования Redis аналогичен тому, как мы используем базы данных. Сначала нам нужно установить сервер Redis на нашем локальном компьютере или сервере Java. клиент интегрируется в программу, а затем операции добавления, удаления, изменения и запроса Redis выполняются через клиент. Для Redis по-прежнему существует множество типов Java-клиентов, наиболее распространенными из них являются jedis, redission, салат и т. д., поэтому при интеграции мы можем выбрать прямую интеграцию этих собственных клиентов. Но более распространенный способ в SpringBoot — интеграция Spring-Data-Redis, проекта, предоставляемого Spring специально для работы с Redis. Он инкапсулирует общие операции Redis и в основном инкапсулирует два клиента jedis и салат. Это эквивалентно добавлению поверх них слоя фасада.

В этой статье мы сосредоточимся на внедрении SpringBoot для использования общих операций в Redis путем интеграции Spring-Data-Redis.

Поскольку проблем с совместимостью нет, мы разрабатываем непосредственно ветку Feature/MybatisPlus.

2. Этапы интеграции

2.1 Добавьте зависимости

Добавьте необходимые зависимости для Redis:

Язык кода:javascript
копировать
<!-- Интеграция зависимостей Redis  -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

Завершить pom.xml

Язык кода:javascript
копировать
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.lsqingfeng.springboot</groupId>
    <artifactId>springboot-learning</artifactId>
    <version>1.0.0</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.6.2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
            <scope>provided</scope>
        </dependency>

        <!-- mybatis-plus необходимые зависимости  -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.1</version>
        </dependency>

        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.31</version>
        </dependency>

        <!-- Горячий старт разработки -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- MySQL-соединение -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- Интеграция зависимостей Redis  -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>
</project>

Здесь мы непосредственно представляем Spring-boot-starter-data-redis, стартер, уже предоставленный самим SpringBoot. Мы можем щелкнуть мышью, чтобы увидеть, какие зависимости включены в этот стартер:

Можно обнаружить, что он содержит два основных пакета: Spring-data-Redis и Lettuce-Core. Вот почему наш Spring-boot-starter-data-redis по умолчанию использует клиент салата.

Что, если мы хотим использовать клиент jedis? Вам просто нужно исключить зависимость от салата, а затем ввести соответствующие зависимости от джедиса.

Так почему же нам нужно вводить только разные зависимости, чтобы Spring-data-redis мог свободно переключать клиентов? На самом деле это включает в себя принцип автоматической настройки SpringBoot. Мы можем дать вам краткое объяснение.

Одной из основных причин, по которой платформа SpringBoot может легко интегрировать другие технологии с помощью различных стартеров, является функция автоматической настройки самой SpringBoot. Так называемая автоматическая конфигурация означает, что SpringBoot сам предварительно установил классы интеграции некоторых распространенных фреймворков. Затем используйте аннотации условного определения, аналогичные ConditionOn, чтобы определить, есть ли в вашем проекте соответствующие классы (или конфигурации), а затем инициализируйте соответствующие конфигурации.

Предустановленные классы автоматической настройки SpringBoot находятся в пакете Spring-boot-autoconfigure. Пока мы создаем проект SpringBoot, этот пакет будет представлен.

В этом пакете есть класс RedisAutoConfiguration, который, как следует из названия, представляет собой автоматическую настройку Redis. В этом классе будут представлены два класса конфигурации LettuceConnectionConfiguration и JedisConnectionConfiguration, соответствующие двум клиентам Lettuce и Jedis соответственно.

Оба класса используют аннотацию ConditionOn, чтобы определить, следует ли загружать.

джедаи следующие;

Поскольку наш проект автоматически вводит салатное ядро ​​без введения зависимостей, связанных с jedis, класс LettuceConnectionConfiguration будет загружен, если суждение истинно, но суждение Jedis неверно, поэтому он не будет загружен. Затем вступает в силу конфигурация салата, поэтому по умолчанию мы используем клиент салата.

2.2 Добавить конфигурацию

Затем нам нужно настроить пароль учетной записи и другую информацию, необходимую для подключения к Redis. Здесь каждый должен заранее установить Redis, чтобы наша локальная программа могла подключиться к нашему Redis. Если вы не знаете, как установить Redis, вы можете обратиться к статье: [Установка redis6.0.5 в системе Linux] https://blog.csdn.net/lsqingfeng/article/details/107359076

Общая конфигурация выглядит следующим образом: Настройте информацию о соединении Redis в файле конфигурации application.yml.

Язык кода:javascript
копировать
spring:
  redis:
    host: localhost
    port: 6379
    password: 123456
    database: 0

Если есть другие конфигурации вместе взятые:

Язык кода:javascript
копировать
server:
  port: 19191

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springboot_learning?serverTimezone=Asia/Shanghai&characterEncoding=utf-8
    username: root
    password: root
  redis:
    host: localhost
    port: 6379
    password: 123456
    database: 0
    lettuce:
      pool:
        max-idle: 16
        max-active: 32
        min-idle: 8
  devtools:
    restart:
      enable: true


third:
  weather:
    url: http://www.baidu.com
    port: 8080
    username: test
    cities:
      - Пекин
      - Шанхай
      - Гуанчжоу
    list[0]: aaa
    list[1]: bbb
    list[2]: ccc

Таким образом, мы можем управлять Redis непосредственно в проекте. Если вы используете кластер, используйте следующую конфигурацию:

Язык кода:javascript
копировать
spring:
  redis:
    password: 123456
    cluster:
      nodes: 10.255.144.115:7001,10.255.144.115:7002,10.255.144.115:7003,10.255.144.115:7004,10.255.144.115:7005,10.255.144.115:7006
      max-redirects: 3

Но иногда нам нужно настроить пул соединений для нашего клиента Redis. Как и при подключении к MySQL, мы также настроим пул соединений. Цель — улучшить управление подключениями к данным, повысить эффективность доступа и обеспечить разумное использование ресурсов. Итак, как нам настроить пул соединений? Каждый должен обратить на это внимание. Во многих онлайн-статьях представленные методы могут быть не особенно точными, поскольку версия слишком низкая. Например, многие используют для настройки Spring.redis.pool, что неверно (не знаю, настроена ли так старая версия, но в Springboot-starter-data-redis такой способ написания неправильный). Первый — это файл конфигурации. Поскольку мы используем клиент салата, при настройке добавьте салат и пул в файл Spring.redis для настройки следующим образом:

Язык кода:javascript
копировать
spring:
  redis:
    host: 10.255.144.111
    port: 6379
    password: 123456
    database: 0
    lettuce:
      pool:
        max-idle: 16
        max-active: 32
        min-idle: 8

Если вы используете jedis, замените салат на jedis (обратите внимание, что зависимости также необходимо заменить).

Но просто добавив это в файл конфигурации, пул соединений не вступит в силу. Здесь каждый должен обратить внимание. Многие студенты добавляют этот параграф в файл конфигурации и думают, что пул соединений настроен. На самом деле это не так. Самый важный шаг — импорт зависимости. Если нет, настройте. это так. Это тоже бесполезно.

Язык кода:javascript
копировать
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

После этого пул соединений вступит в силу. Мы можем провести сравнение. Вы можете убедиться в этом, наблюдая за значением объекта RedisTemplate до и после импорта пакета.

Перед импортом:

После импорта:

Информация о нашем пуле соединений будет иметь ценность только после присоединения к компании, что также подтверждает наш вывод, сделанный выше.

Для получения конкретной информации о конфигурации мы можем просмотреть исходный код. Класс RedisProperties используется в исходном коде для получения параметров конфигурации Redis.

2.3 Использование в проектах

После того, как наша работа по настройке будет готова, мы сможем использовать Redis в проекте. Если мы это сделаем, мы сможем использовать класс RedisTemplate, предоставленный нам в Spring-data-Redis. Давайте сначала рассмотрим простой пример, вставив пару ключ-значение (значение — строка).

Язык кода:javascript
копировать
package com.lsqingfeng.springboot.controller;

import com.lsqingfeng.springboot.base.Result;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @className: RedisController
 * @description:
 * @author: sh.Liu
 * @date: 2022-03-08 14:28
 */
@RestController
@RequestMapping("redis")
public class RedisController {

    private final RedisTemplate redisTemplate;

    public RedisController(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @GetMapping("save")
    public Result save(String key, String value){
        redisTemplate.opsForValue().set(key, value);
        return Result.success();
    }

}

3. Инкапсуляция инструмента

Мы успешно управляли сервером Redis через RedisTemplate в предыдущем коде. Например, чтобы установить строку, мы можем использовать:

Язык кода:javascript
копировать
redisTemplate.opsForValue().set(key, value);

Чтобы поместить пару ключ-значение типа String. Redis может поддерживать пять форматов данных: строка, список, хэш, набор и zset. Общие операции этих пяти форматов данных инкапсулированы в класс RedisTemplate. Для работы со строковым типом используйте opsForValue, для работы со списком — используйте listOps, для работы с набором — используйте setOps и т. д. Мы можем узнать об общих функциях, просмотрев исходный код класса RedisTemplate.

Все эти функции находятся в этом классе, что не очень удобно использовать. Обычно мы инкапсулируем класс инструмента отдельно, чтобы абстрагировать некоторые часто используемые методы. При работе действуйте непосредственно через класс инструмента.

Язык кода:javascript
копировать
package com.lsqingfeng.springboot.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @className: RedisUtil
 * @description:
 * @author: sh.Liu
 * @date: 2022-03-09 14:07
 */
@Component
public class RedisUtil {

    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * дать назначенное key Срок действия добавленного значения
     *
     * @param key
     * @param time
     * @return
     */
    public boolean expire(String key, long time) {
        return redisTemplate.expire(key, time, TimeUnit.SECONDS);
    }
    /**
     * Согласно ключевому Получить срок годности
     *
     * @param key
     * @return
     */
    public long getTime(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }
    /**
     * Согласно ключевому Получить срок годности
     *
     * @param key
     * @return
     */
    public boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }
    /**
     * Удалить указанный ключ срок годности
     *
     * @param key
     * @return
     */
    public boolean persist(String key) {
        return redisTemplate.boundValueOps(key).persist();
    }

    //- - - - - - - - - - - - - - - - - - - - -  Тип строки - - - - - - - - - - - - - - - - - - - -

    /**
     * Согласно ключевому Получатьценить
     *
     * @param key ключ
     * @return ценить
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }

    /**
     * Поместить ценить в кэш
     *
     * @param key   ключ
     * @param value ценить
     * @return настоящий успех false неудача
     */
    public void set(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * Поместить ценить в кэш并设置时间
     *
     * @param key   ключ
     * @param value ценить
     * @param time  время (секунды) -1 означает неограниченный
     * @return настоящий успех false неудача
     */
    public void set(String key, String value, long time) {
        if (time > 0) {
            redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
        } else {
            redisTemplate.opsForValue().set(key, value);
        }
    }

    /**
     * Добавлять партиями key (Повторный выбор будет перезаписан)
     *
     * @param keyAndValue
     */
    public void batchSet(Map<String, String> keyAndValue) {
        redisTemplate.opsForValue().multiSet(keyAndValue);
    }

    /**
     * Добавлять партиями key-value Только в ключне Добавлять только тогда, когда существует
     * map середина Пока существует один ключ, ни один не будет добавлен.
     *
     * @param keyAndValue
     */
    public void batchSetIfAbsent(Map<String, String> keyAndValue) {
        redisTemplate.opsForValue().multiSetIfAbsent(keyAndValue);
    }

    /**
     * одному key-value изценить выполнять операции сложения и вычитания,
     * Если key не существует Ключ будет создан. И назначить ценить number
     * если key существует, но value Не длинное целое число , сообщит об ошибке
     *
     * @param key
     * @param number
     */
    public Long increment(String key, long number) {
        return redisTemplate.opsForValue().increment(key, number);
    }

    /**
     * одному key-value изценить выполнять операции сложения и вычитания,
     * Если key не существует Ключ будет создан. И назначить ценить number
     * если key существует, но value нет чистые числа , сообщит об ошибке
     *
     * @param key
     * @param number
     */
    public Double increment(String key, double number) {
        return redisTemplate.opsForValue().increment(key, number);
    }

    //- - - - - - - - - - - - - - - - - - - - -  тип установки - - - - - - - - - - - - - - - - - - - -

    /**
     * Поместить данные в установленный кеш
     *
     * @param key ключ
     * @return
     */
    public void sSet(String key, String value) {
        redisTemplate.opsForSet().add(key, value);
    }

    /**
     * Получатьпеременнаясерединаизценить
     *
     * @param key ключ
     * @return
     */
    public Set<Object> members(String key) {
        return redisTemplate.opsForSet().members(key);
    }

    /**
     * Случайным образом получить указанное количество элементов из переменной середина
     *
     * @param key   ключ
     * @param count ценить
     * @return
     */
    public void randomMembers(String key, long count) {
        redisTemplate.opsForSet().randomMembers(key, count);
    }

    /**
     * Случайным образом получить элементы переменной середина
     *
     * @param key ключ
     * @return
     */
    public Object randomMember(String key) {
        return redisTemplate.opsForSet().randomMember(key);
    }

    /**
     * Вытолкните элемент переменной середина
     *
     * @param key ключ
     * @return
     */
    public Object pop(String key) {
        return redisTemplate.opsForSet().pop("setValue");
    }

    /**
     * Получатьпеременнаясерединаценитьиз长度
     *
     * @param key ключ
     * @return
     */
    public long size(String key) {
        return redisTemplate.opsForSet().size(key);
    }

    /**
     * Запрос из наборасередина на основе значения, существует ли оно
     *
     * @param key   ключ
     * @param value ценить
     * @return true существовать falseне существует
     */
    public boolean sHasKey(String key, Object value) {
        return redisTemplate.opsForSet().isMember(key, value);
    }

    /**
     * Проверяет, находится ли данный элемент в переменной середина.
     *
     * @param key ключ
     * @param obj элемент объекта
     * @return
     */
    public boolean isMember(String key, Object obj) {
        return redisTemplate.opsForSet().isMember(key, obj);
    }

    /**
     * 转移переменнаяизэлементценить До сих поризпеременная。
     *
     * @param key     ключ
     * @param value   элемент объекта
     * @param destKey элемент объекта
     * @return
     */
    public boolean move(String key, String value, String destKey) {
        return redisTemplate.opsForSet().move(key, value, destKey);
    }

    /**
     * Удалить набор элементов кэша середина в пакетном режиме
     *
     * @param key    ключ
     * @param values ценить
     * @return
     */
    public void remove(String key, Object... values) {
        redisTemplate.opsForSet().remove(key, values);
    }

    /**
     * по данномуизkeyпросить2индивидуальныйsetпеременнаяиз Разницаценить
     *
     * @param key     ключ
     * @param destKey ключ
     * @return
     */
    public Set<Set> difference(String key, String destKey) {
        return redisTemplate.opsForSet().difference(key, destKey);
    }


    //- - - - - - - - - - - - - - - - - - - - -  тип хеша - - - - - - - - - - - - - - - - - - - -

    /**
     * Добавить в кэш
     *
     * @param key ключ
     * @param map ключ
     * @return
     */
    public void add(String key, Map<String, String> map) {
        redisTemplate.opsForHash().putAll(key, map);
    }

    /**
     * Получать key вниз все  hashkey и value
     *
     * @param key ключ
     * @return
     */
    public Map<Object, Object> getHashEntries(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * Проверьте обозначение key Вниз Есть ли какой-либо указанный hashkey
     *
     * @param key
     * @param hashKey
     * @return
     */
    public boolean hashKey(String key, String hashKey) {
        return redisTemplate.opsForHash().hasKey(key, hashKey);
    }

    /**
     * Получатьобозначениеkeyизценитьstring
     *
     * @param key  ключ
     * @param key2 ключ
     * @return
     */
    public String getMapString(String key, String key2) {
        return redisTemplate.opsForHash().get("map1", "key1").toString();
    }

    /**
     * ПолучатьобозначениеизценитьInt
     *
     * @param key  ключ
     * @param key2 ключ
     * @return
     */
    public Integer getMapInt(String key, String key2) {
        return (Integer) redisTemplate.opsForHash().get("map1", "key1");
    }

    /**
     * Вытащить элемент и удалить
     *
     * @param key ключ
     * @return
     */
    public String popValue(String key) {
        return redisTemplate.opsForSet().pop(key).toString();
    }

    /**
     * Удалить указанное hash из HashKey
     *
     * @param key
     * @param hashKeys
     * @return удалитьуспехиз количество
     */
    public Long delete(String key, String... hashKeys) {
        return redisTemplate.opsForHash().delete(key, hashKeys);
    }

    /**
     * назначать hash из hashkey Увеличьте или уменьшите операции
     *
     * @param key
     * @param hashKey
     * @param number
     * @return
     */
    public Long increment(String key, String hashKey, long number) {
        return redisTemplate.opsForHash().increment(key, hashKey, number);
    }

    /**
     * назначать hash из hashkey Увеличьте или уменьшите операции
     *
     * @param key
     * @param hashKey
     * @param number
     * @return
     */
    public Double increment(String key, String hashKey, Double number) {
        return redisTemplate.opsForHash().increment(key, hashKey, number);
    }

    /**
     * Получать key вниз все hashkey Поле
     *
     * @param key
     * @return
     */
    public Set<Object> hashKeys(String key) {
        return redisTemplate.opsForHash().keys(key);
    }

    /**
     * Получатьобозначение hash Внизлапшаиз ключценить пару количество
     *
     * @param key
     * @return
     */
    public Long hashSize(String key) {
        return redisTemplate.opsForHash().size(key);
    }

    //- - - - - - - - - - - - - - - - - - - - -  тип списка - - - - - - - - - - - - - - - - - - - -

    /**
     * 在переменнаялевый添加элементценить
     *
     * @param key
     * @param value
     * @return
     */
    public void leftPush(String key, Object value) {
        redisTemplate.opsForList().leftPush(key, value);
    }

    /**
     * Получатьсобиратьобозначение位置изценить。
     *
     * @param key
     * @param index
     * @return
     */
    public Object index(String key, long index) {
        return redisTemplate.opsForList().index("list", 1);
    }

    /**
     * Получатьобозначение区间изценить。
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public List<Object> range(String key, long start, long end) {
        return redisTemplate.opsForList().range(key, start, end);
    }

    /**
     * 把最后一индивидуальный参数ценить放приезжатьобозначениесобиратьиз第一индивидуальный出现серединапараметры временииз前лапша,
     * еслисерединапараметры времениценитьсуществоватьизразговаривать。
     *
     * @param key
     * @param pivot
     * @param value
     * @return
     */
    public void leftPush(String key, String pivot, String value) {
        redisTemplate.opsForList().leftPush(key, pivot, value);
    }

    /**
     * Слева Добавить партиями参数элемент。
     *
     * @param key
     * @param values
     * @return
     */
    public void leftPushAll(String key, String... values) {
//        redisTemplate.opsForList().leftPushAll(key,"w","x","y");
        redisTemplate.opsForList().leftPushAll(key, values);
    }

    /**
     * Добавляет элемент в самый правый элемент коллекции.
     *
     * @param key
     * @param value
     * @return
     */
    public void leftPushAll(String key, String value) {
        redisTemplate.opsForList().rightPush(key, value);
    }

    /**
     * Слева Добавить партиями参数элемент。
     *
     * @param key
     * @param values
     * @return
     */
    public void rightPushAll(String key, String... values) {
        //redisTemplate.opsForList().leftPushAll(key,"w","x","y");
        redisTemplate.opsForList().rightPushAll(key, values);
    }

    /**
     * Сян Исуществоватьизсобиратьсередина添加элемент。
     *
     * @param key
     * @param value
     * @return
     */
    public void rightPushIfPresent(String key, Object value) {
        redisTemplate.opsForList().rightPushIfPresent(key, value);
    }

    /**
     * Сян Исуществоватьизсобиратьсередина添加элемент。
     *
     * @param key
     * @return
     */
    public long listLength(String key) {
        return redisTemplate.opsForList().size(key);
    }

    /**
     * 移除собиратьсерединаизлевый第一индивидуальныйэлемент。
     *
     * @param key
     * @return
     */
    public void leftPop(String key) {
        redisTemplate.opsForList().leftPop(key);
    }

    /**
     * 移除собиратьсерединалевыйизэлемент在等待извремя,еслибольше, чем ожиданиеиз时间仍没иметьэлементно退出。
     *
     * @param key
     * @return
     */
    public void leftPop(String key, long timeout, TimeUnit unit) {
        redisTemplate.opsForList().leftPop(key, timeout, unit);
    }

    /**
     * 移除собиратьсерединаверноизэлемент。
     *
     * @param key
     * @return
     */
    public void rightPop(String key) {
        redisTemplate.opsForList().rightPop(key);
    }

    /**
     * 移除собиратьсерединаверноизэлемент在等待извремя,еслибольше, чем ожиданиеиз时间仍没иметьэлементно退出。
     *
     * @param key
     * @return
     */
    public void rightPop(String key, long timeout, TimeUnit unit) {
        redisTemplate.opsForList().rightPop(key, timeout, unit);
    }
}

Вы также можете прочитать этот класс инструментов, чтобы узнать больше об использовании RedisTemplate. При его использовании вам нужно только внедрить этот класс инструмента.

4. Поговорим о сериализации

redisиз Сериализация также является тем, что мы используемRedisTemplateизпроцесссерединанужно вниманиеизиметь значение。上лапшаиз Случайсередина,На самом деле никаких особых настроек у нас нет.redisиз Метод сериализации,тогда он действительно используетизэто значение по умолчаниюиз Метод сериализации。RedisTemplate这индивидуальный类из Дженерики<String,Object>,То есть, он поддерживает записьObjectобъектиз,那么这индивидуальныйобъект采取什么方式序列化存入内存серединавот и всеиз Метод сериализации。

Так что же такое сериализация Redis? Это означает, что мы храним объекты в Redis. Это могут быть двоичные данные, xml или json. Например, мы часто используем POJO. хранилище объектовприезжать Redis , обычно используется JSON метод сериализуется в строку и сохраняется в Redis середина 。

Сам Redis предоставляет метод сериализации:

  • GenericToStringSerializer: может обобщить любой объект в строку и сериализовать его.
  • Jackson2JsonRedisSerializer: фактически то же самое, что и JacksonJsonRedisSerializer.
  • JacksonJsonRedisSerializer: сериализовать объект объекта в строку json
  • JdkSerializationRedisSerializer: сериализация объектов Java
  • StringRedisSerializer: простая сериализация строк.

Если мы храним тип String, методом сериализации по умолчанию является StringRedisSerializer. Если мы храним объекты, по умолчанию используется JdkSerializationRedisSerializer, который представляет собой метод сериализации Jdk (реализуемый через ObjectOutputStream и ObjectInputStream. Недостаток заключается в том, что мы не можем интуитивно видеть содержимое хранимых объектов).

Мы можем установить соответствующий метод сериализации в соответствии с различными типами данных, которыми управляет Redis.

Наблюдая за исходным кодом RedisTemplate, мы видим, что по умолчанию используется JdkSerializationRedisSerializer. Самая большая проблема такого типа сериализации заключается в том, что после сохранения объекта нам сложно визуально увидеть хранимый контент, что очень неудобно. нам для решения проблем:

Как правило, наиболее часто используемый метод сериализации объектов: Jackson2JsonRedisSerializer.

设置Метод сериализациииз Основной метод заключается в том, что мы настраиваем класссередина,Создайте объект RedisTemplate самостоятельно.,и создатьизпроцесссерединаобозначение对应из Метод сериализации。

Язык кода:javascript
копировать
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {
    @Bean(name = "redisTemplate")
    public RedisTemplate<String, Object> getRedisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        redisTemplate.setConnectionFactory(factory);
        
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        
        redisTemplate.setKeySerializer(stringRedisSerializer); // ключиз типа сериализации

        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // Срок действия метода истек,Изменить на Внизлапша代码
//        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance ,
                ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
       
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); // значениеиз типа сериализации
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

используйте вот такизкогда,будет установлен в соответствии с нашимизjsonМетод сериализации进行存储,Мы также можемredisсередина Посмотреть контентизвремя удобноеиз查看приезжать属性ценить。

5. Распределенная блокировка

Ссылки:

7 способов реализовать распределенные блокировки с помощью Redis —Why414 — Blog Park

Много сценсередина,Нужно использоватьраспределенныйдела、распределенный Блокировки и другие технологии для обеспечения конечной согласованности данных.。иметьизкогда,Нам нужно гарантировать, что определенный метод может выполняться только одним потоком одновременно. В автономной (однопроцессной) среде середина,JAVA предоставляет множество API-интерфейсов, связанных с параллелизмом.,Но в многомашинной (многопроцессной) среде вы ничего не сможете сделать.

Для распределенных блокировок лучше всего соблюдать следующие пункты.

可以保证在распределенныйразвертыватьизкластер приложенийсередина,同一индивидуальный方法在同一时间只能被一台机器上из一индивидуальный线程执行 Если эта блокировка является реентерабельной (чтобы избежать взаимоблокировки) Этот замок предпочтительно является блокирующим замком. Высокодоступные функции захвата и снятия блокировки Улучшена производительность захвата и снятия блокировок.

Обычно существует три способа реализации распределенных блокировок: 1. Оптимистическая блокировка базы данных. 2. Распределенная блокировка на основе Redis. 3. Распределенная блокировка на основе ZooKeeper. В этой статье в основном представлен второй метод.

Идеальная распределенная блокировка должна соответствовать следующим четырем условиям: 1. Взаимная исключительность. В любой момент только один клиент может удерживать блокировку. 2. Тупика не произойдет. Даже если клиент выйдет из строя, удерживая блокировку без ее активной разблокировки, гарантируется, что другие клиенты впоследствии смогут ее заблокировать. 3. Отказоустойчивость. Пока большинство узлов Redis работают нормально, клиент может блокировать и разблокировать. 4. Чтобы развязать колокольчик, надо колокольчик завязать. Блокировка и разблокировка должны выполняться одним и тем же клиентом. Сам клиент не может разблокировать блокировку, добавленную другими.

Принцип распределенной блокировки Redis:

Замокиз Реализация в основном основана наredisизSETNXЗаказ

SETNX key value将 key Значение установлено на value , тогда и только тогда, когда key Не существует. Если дано key уже существует, то SETNX Никаких действий не предпринимается. SETNX Это "SET" if Not существует» (если его не существует, то Сокращение от SET).

**Возвращаемое значение:** Если настройка выполнена успешно, будет возвращено 1. Установка завершается с ошибкой и возвращает 0.

использоватьSETNX完成同步Замокиз Такие процессы и вопросы, как Вниз:

  1. использоватьSETNXЗаказ Получать Замок,Если он возвращает 0 (ключ существовал,Замокужесуществовать)но Получатьнеудача,Напротив Получатьуспех
  2. 为了防止Получать Замок后程序出现异常,перейди в другие темы/вызов процессаSETNXЗаказ总是返回0而进入死Замок状态,需要为Долженkey设置一индивидуальный“Разумный”срок годности
  3. разблокировать замок,использоватьDELЗаказ将Замок数据удалить

Эта статьясерединадляRedisсерединаиз Замокиз介绍还是比较全лапшаиз。

8 основных ошибок при реализации распределенных блокировок с помощью Redis! Помнить! -технический кружок

Существует множество способов реализации блокировок Redis, которые могут вызвать некоторые проблемы. Относительно идеальное решение — использовать скрипты Lua. Самое идеальное решение — использовать RedissionRedLock в рамках Redission. Конкретная реализация не будет приведена. Вы можете следовать этой идее, чтобы найти соответствующую информацию. Я вернусь и добавлю больше, когда у меня будет время и силы.

boy illustration
Углубленный анализ переполнения памяти CUDA: OutOfMemoryError: CUDA не хватает памяти. Попыталась выделить 3,21 Ги Б (GPU 0; всего 8,00 Ги Б).
boy illustration
[Решено] ошибка установки conda. Среда решения: не удалось выполнить первоначальное зависание. Повторная попытка с помощью файла (графическое руководство).
boy illustration
Прочитайте нейросетевую модель Трансформера в одной статье
boy illustration
.ART Теплые зимние предложения уже открыты
boy illustration
Сравнительная таблица описания кодов ошибок Amap
boy illustration
Уведомление о последних правилах Points Mall в декабре 2022 года.
boy illustration
Даже новички могут быстро приступить к работе с легким сервером приложений.
boy illustration
Взгляд на RSAC 2024|Защита конфиденциальности в эпоху больших моделей
boy illustration
Вы используете ИИ каждый день и до сих пор не знаете, как ИИ дает обратную связь? Одна статья для понимания реализации в коде Python общих функций потерь генеративных моделей + анализ принципов расчета.
boy illustration
Используйте (внутренний) почтовый ящик для образовательных учреждений, чтобы использовать Microsoft Family Bucket (1T дискового пространства на одном диске и версию Office 365 для образовательных учреждений)
boy illustration
Руководство по началу работы с оперативным проектом (7) Практическое сочетание оперативного письма — оперативного письма на основе интеллектуальной системы вопросов и ответов службы поддержки клиентов
boy illustration
[docker] Версия сервера «Чтение 3» — создайте свою собственную программу чтения веб-текста
boy illustration
Обзор Cloud-init и этапы создания в рамках PVE
boy illustration
Корпоративные пользователи используют пакет регистрационных ресурсов для регистрации ICP для веб-сайта и активации оплаты WeChat H5 (с кодом платежного узла версии API V3)
boy illustration
Подробное объяснение таких показателей производительности с высоким уровнем параллелизма, как QPS, TPS, RT и пропускная способность.
boy illustration
Удачи в конкурсе Python Essay Challenge, станьте первым, кто испытает новую функцию сообщества [Запускать блоки кода онлайн] и выиграйте множество изысканных подарков!
boy illustration
[Техническая посадка травы] Кровавая рвота и отделка позволяют вам необычным образом ощипывать гусиные перья! Не распространяйте информацию! ! !
boy illustration
[Официальное ограниченное по времени мероприятие] Сейчас ноябрь, напишите и получите приз
boy illustration
Прочтите это в одной статье: Учебник для няни по созданию сервера Huanshou Parlu на базе CVM-сервера.
boy illustration
Cloud Native | Что такое CRD (настраиваемые определения ресурсов) в K8s?
boy illustration
Как использовать Cloudflare CDN для настройки узла (CF самостоятельно выбирает IP) Гонконг, Китай/Азия узел/сводка и рекомендации внутреннего высокоскоростного IP-сегмента
boy illustration
Дополнительные правила вознаграждения амбассадоров акции в марте 2023 г.
boy illustration
Можно ли открыть частный сервер Phantom Beast Palu одним щелчком мыши? Супер простой урок для начинающих! (Прилагается метод обновления сервера)
boy illustration
[Играйте с Phantom Beast Palu] Обновите игровой сервер Phantom Beast Pallu одним щелчком мыши
boy illustration
Maotouhu делится: последний доступный внутри страны адрес склада исходного образа Docker 2024 года (обновлено 1 декабря)
boy illustration
Кодирование Base64 в MultipartFile
boy illustration
5 точек расширения SpringBoot, супер практично!
boy illustration
Глубокое понимание сопоставления индексов Elasticsearch.
boy illustration
15 рекомендуемых платформ разработки с нулевым кодом корпоративного уровня. Всегда найдется та, которая вам понравится.
boy illustration
Аннотация EasyExcel позволяет экспортировать с сохранением двух десятичных знаков.