>  기사  >  데이터 베이스  >  SpringBoot가 Redis를 통합하여 높은 동시 데이터 캐싱을 달성하는 방법

SpringBoot가 Redis를 통합하여 높은 동시 데이터 캐싱을 달성하는 방법

WBOY
WBOY앞으로
2023-05-27 21:24:121176검색

캐시란?

캐시는 데이터를 빠르게 접근하고 운용하는데 사용할 수 있는 고속 데이터 교환을 위한 메모리입니다.

간단한 예를 들어보겠습니다.

샤오밍은 식당을 열었을 때 평판이 좋지 않았고 손님도 적어서 별로 바쁘지 않았습니다. 그는 주로 할 일이 없을 때 한가하게 있었고, 손님이 오면 요리를 준비하기 위해 주방에 들어갔습니다. 왔다. 호텔의 발전이 증가함에 따라 현재의 호텔은 과거와 달리 안정적인 고객이 많으며 특정 휴일에는 심지어 만석입니다. 이전 관행에 따르면, 성수기에는 식사 준비가 늦어 고객이 오랜 시간 기다려야 하여 호텔 측에 불만이 반복적으로 발생했습니다.
이 문제를 해결하기 위해 샤오밍은 한가할 때 인기 있는 요리를 미리 조리해 보온 캐비닛에 넣어두었다가 피크타임에 꺼내서 데울 수 있는 방법을 생각해 냈습니다. 이 방법은 피크 시간대에도 많은 수의 고객이 식사를 준비하는 데 어려움을 겪는 문제를 해결합니다.

캐싱의 핵심은 자주 액세스하는 리소스(고빈도 읽기, 저주파 쓰기)를 사용자와 가장 가까운 위치에 미리 저장하고 액세스 속도를 빠르게 하여 액세스 속도를 향상시키는 것입니다.

캐싱을 사용하는 이유

캐싱을 사용하면 효율성이 크게 향상되고 불필요한 리소스 소비가 줄어들며 사용자 경험이 향상됩니다.

redis의 기능:

  • redis는 데이터 지속성을 지원합니다. 메모리의 데이터는 디스크에 저장할 수 있으며 다시 시작할 때 다시 사용할 수 있습니다.

  • redis는 단순한 키-값 형식의 데이터를 지원할 뿐만 아니라 list, set, zset, hash 등과 같은 데이터 구조의 저장도 제공합니다.

  • redis는 데이터 백업, 즉 마스터에 데이터 백업을 지원합니다. -슬레이브 모드

redis의 장점:

  • 매우 높은 성능 - Redis는 110,000회/초의 속도로 읽고 81,000회/초의 속도로 쓸 수 있습니다.

  • 다양한 데이터 유형 - redis는 이진 사례에 대한 문자열, 목록, 해시, 세트 및 순서 세트 데이터 유형 작업을 지원합니다.

  • Atomic - Redis의 모든 작업은 원자적입니다. 즉, 성공적으로 실행되거나 실패할 경우 전혀 실행되지 않습니다. 개별 작업은 원자적입니다. 다중 작업은 multi 및 exec 명령어로 래핑된 트랜잭션, 즉 원자성도 지원합니다.

  • 풍부한 기능 redis는 게시/구독, 알림, 키 만료 및 기타 기능도 지원합니다.

Redis가 왜 그렇게 빠른가요?

(1) 완전히 메모리를 기반으로 하며 데이터는 메모리에 저장되며 대부분의 요청은 순수 메모리입니다. 기존 디스크 파일 데이터 스토리지에 비해 작업 속도가 매우 빠르므로 디스크 IO를 통해 메모리를 읽는 오버헤드가 발생하지 않습니다.

(2) 데이터 구조가 간단하고 데이터 연산도 간단합니다. 각 데이터 구조는 Redis에서 특별히 설계된 하나 이상의 데이터 구조에 의해 지원됩니다. Redis는 이러한 유연한 데이터 구조를 활용하여 읽기 및 쓰기 성능을 향상합니다.

(3) 단일 스레드를 사용하면 컨텍스트 전환 시간과 CPU 소비가 많이 절약됩니다. 경쟁 조건이 없고 다양한 잠금 문제를 고려할 필요가 없으며 잠금 작업을 잠그고 해제할 필요도 없습니다. 교착 상태로 인해 성능이 소모됩니다.

(4) IO 다중화 메커니즘을 기반으로 하는 스레드 모델을 사용하면 동시 링크를 처리할 수 있습니다.

사용자 정보 캐시 구현

데이터베이스 테이블 구조:

CREATE TABLE `blade_user` (
  `id` bigint(20) NOT NULL COMMENT '主键',
  `tenant_id` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '000000' COMMENT '租户ID',
  `code` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '用户编号',
  `user_type` int(11) DEFAULT NULL COMMENT '用户平台',
  `account` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '账号',
  `password` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '密码',
  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '昵称',
  `real_name` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '真名',
  `avatar` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '头像',
  `email` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '邮箱',
  `phone` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '手机',
  `birthday` datetime DEFAULT NULL COMMENT '生日',
  `sex` int(11) DEFAULT NULL COMMENT '性别',
  `role_id` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '角色id',
  `dept_id` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '部门id',
  `post_id` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '岗位id',
  `create_user` bigint(20) DEFAULT NULL COMMENT '创建人',
  `create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_user` bigint(20) DEFAULT NULL COMMENT '修改人',
  `update_time` datetime DEFAULT NULL COMMENT '修改时间',
  `status` int(11) DEFAULT NULL COMMENT '状态',
  `is_deleted` int(11) DEFAULT '0' COMMENT '是否已删除',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='用户表';

방법 1: RedisTemplate을 사용하여 가져오기 종속성 구현

pom.xml 파일 완료:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.8</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.redis.demo</groupId>
    <artifactId>springboot-redis</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-redis</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>

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


        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--mybatis-plus的springboot支持-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.15</version>
        </dependency>

       <!-- hutool 工具包,各种封装功能 一应俱全-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.5</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.41</version>
        </dependency>

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

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
구성 추가

application.yml 파일:

server:
  port: 8081

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://3.129.36.183:3306/test?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8
    username: root
    password: root
  #redis
  redis:
    host: 3.129.36.183
    #Redis服务器连接端口
    port: 6379
    #Redis服务器连接密码
    password: 123456

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启sql日志
    # 将带有下划线的表字段映射为驼峰格式的实体类属性
    map-underscore-to-camel-case: true
  #配置类型别名所对应的包
  type-aliases-package: com.redis.demo.entity
  #配置SQL输出语句com.winsun.dataclean.mapper
  mapper-locations: com/redis/demo/dao/*.xml
Add redis 도구 클래스 및 구성 클래스

RedisUtils:

package com.redis.demo.utils;

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

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

/**
 * Redis工具类
 *
 * @author
 */
@Component
public class RedisUtils {


    @Autowired
    private RedisTemplate redisTemplate;

    // =============================common============================

    /**
     * 指定缓存失效时间
     *
     * @param key  键
     * @param time 时间(秒)
     * @return
     */
    public boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据key 获取过期时间
     *
     * @param key 键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判断key是否存在
     *
     * @param key 键
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除缓存
     *
     * @param key 可以传一个值 或多个
     */
    @SuppressWarnings("unchecked")
    public void del(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                redisTemplate.delete(key[0]);
            } else {
                redisTemplate.delete(CollectionUtils.arrayToList(key));
            }
        }
    }

    // ============================String=============================

    /**
     * 普通缓存获取
     *
     * @param key 键
     * @return 值
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }

    /**
     * 普通缓存放入
     *
     * @param key   键
     * @param value 值
     * @return true成功 false失败
     */
    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 普通缓存放入并设置时间
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
     * @return true成功 false 失败
     */
    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 递增
     *
     * @param key   键
     * @param delta 要增加几(大于0)
     * @return
     */
    public long incr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递增因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 递减
     *
     * @param key   键
     * @param delta 要减少几(小于0)
     * @return
     */
    public long decr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递减因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }

    // ================================Map=================================

    /**
     * HashGet
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return 值
     */
    public Object hget(String key, String item) {
        return redisTemplate.opsForHash().get(key, item);
    }

    /**
     * 获取hashKey对应的所有键值
     *
     * @param key 键
     * @return 对应的多个键值
     */
    public Map<Object, Object> hmget(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * HashSet
     *
     * @param key 键
     * @param map 对应多个键值
     * @return true 成功 false 失败
     */
    public boolean hmset(String key, Map<String, Object> map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * HashSet 并设置时间
     *
     * @param key  键
     * @param map  对应多个键值
     * @param time 时间(秒)
     * @return true成功 false失败
     */
    public boolean hmset(String key, Map<String, Object> map, long time) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value, long time) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除hash表中的值
     *
     * @param key  键 不能为null
     * @param item 项 可以使多个 不能为null
     */
    public void hdel(String key, Object... item) {
        redisTemplate.opsForHash().delete(key, item);
    }

    /**
     * 判断hash表中是否有该项的值
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return true 存在 false不存在
     */
    public boolean hHasKey(String key, String item) {
        return redisTemplate.opsForHash().hasKey(key, item);
    }

    /**
     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
     *
     * @param key  键
     * @param item 项
     * @param by   要增加几(大于0)
     * @return
     */
    public double hincr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, by);
    }

    /**
     * hash递减
     *
     * @param key  键
     * @param item 项
     * @param by   要减少记(小于0)
     * @return
     */
    public double hdecr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, -by);
    }

    // ============================set=============================

    /**
     * 根据key获取Set中的所有值
     *
     * @param key 键
     * @return
     */
    public Set<Object> sGet(String key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据value从一个set中查询,是否存在
     *
     * @param key   键
     * @param value 值
     * @return true 存在 false不存在
     */
    public boolean sHasKey(String key, Object value) {
        try {
            return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将数据放入set缓存
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSet(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 将set数据放入缓存
     *
     * @param key    键
     * @param time   时间(秒)
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSetAndTime(String key, long time, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0)
                expire(key, time);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 获取set缓存的长度
     *
     * @param key 键
     * @return
     */
    public long sGetSetSize(String key) {
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 移除值为value的
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 移除的个数
     */
    public long setRemove(String key, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    // ===============================list=================================

    /**
     * 获取list缓存的内容
     *
     * @param key   键
     * @param start 开始
     * @param end   结束 0 到 -1代表所有值
     * @return
     */
    public List<Object> lGet(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取list缓存的长度
     *
     * @param key 键
     * @return
     */
    public long lGetListSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 通过索引 获取list中的值
     *
     * @param key   键
     * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
     * @return
     */
    public Object lGetIndex(String key, long index) {
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public boolean lSet(String key, Object value, long time) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0)
                expire(key, time);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public boolean lSet(String key, List<Object> value, long time) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0)
                expire(key, time);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据索引修改list中的某条数据
     *
     * @param key   键
     * @param index 索引
     * @param value 值
     * @return
     */
    public boolean lUpdateIndex(String key, long index, Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 移除N个值为value
     *
     * @param key   键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */
    public long lRemove(String key, long count, Object value) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
}

RedisConfig:

package com.redis.demo.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.redis.demo.utils.MapUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.interceptor.KeyGenerator;
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.RedisSerializer;

import javax.annotation.PostConstruct;
import java.util.Map;

/**
 * @Author: laz
 * @CreateTime: 2023-02-20  11:55
 * @Version: 1.0
 *
 * 序列化
 */
@Configuration
public class RedisConfig {


    @Autowired
    private RedisTemplate redisTemplate;

    @PostConstruct
    public void init() {
        initRedisTemplate();
    }

    private void initRedisTemplate() {
        RedisSerializer stringSerializer = redisTemplate.getStringSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(stringSerializer);
    }
}

매퍼 인터페이스 개발

package com.redis.demo.dao;


import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.redis.demo.entity.BladeUser;

/**
 * <p>
 * 用户表 Mapper 接口
 * </p>
 *
 * @author laz
 * @since 2023-03-09
 */
public interface BladeUserMapper extends BaseMapper<BladeUser> {

}
service layer

IBladeUserService:

package com.redis.demo.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.redis.demo.entity.BladeUser;
import com.redis.demo.result.DealResult;

/**
 * <p>
 * 用户表 服务类
 * </p>
 *
 * @author laz
 * @since 2023-03-09
 */
public interface IBladeUserService extends IService<BladeUser> {



    DealResult getById(Long id);
}

BladeUserServiceImpl:

package com.redis.demo.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.redis.demo.constant.RedisConstants;
import com.redis.demo.dao.BladeUserMapper;
import com.redis.demo.entity.BladeUser;
import com.redis.demo.result.DealResult;
import com.redis.demo.service.IBladeUserService;
import com.redis.demo.status.CacheNameStatus;
import com.redis.demo.utils.RedisUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author laz
 * @since 2023-03-09
 */
@Service
public class BladeUserServiceImpl extends ServiceImpl<BladeUserMapper, BladeUser> implements IBladeUserService {


    @Autowired
    private  RedisUtils redisUtils;

    @Override
    public DealResult getById(Long id) {

        String userKey = RedisConstants.CACHE_USER_KEY+id;
        Object user = redisUtils.get(userKey);
        if (!ObjectUtils.isEmpty(user)){

            return DealResult.data(JSONUtil.toBean(JSONUtil.toJsonStr(user),BladeUser.class));
        }

        BladeUser bladeUser = baseMapper.selectById(id);
        redisUtils.set(userKey, JSON.toJSONString(bladeUser));
        return DealResult.data(bladeUser);
    }

}
controller layer
package com.redis.demo.controller;
import com.redis.demo.result.DealResult;
import com.redis.demo.service.IBladeUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RestController;

/**
 * <p>
 * 用户表 前端控制器
 * </p>
 *
 * @author laz
 * @since 2023-03-09
 */
@RestController
@RequestMapping("/bladeUser")
public class BladeUserController {

    @Autowired
    private IBladeUserService bladeUserService;

    @RequestMapping("getById/{id}")
    public DealResult getById(@PathVariable("id")Long id){
        return bladeUserService.getById(id);
    }

}
Test

프로젝트를 시작하고 postman을 사용하여 이 인터페이스에 액세스하고 두 번의 연속 요청을 수행하고 응답 시간을 관찰하십시오.

첫 번째 시간:

SpringBoot가 Redis를 통합하여 높은 동시 데이터 캐싱을 달성하는 방법

두 번째 시간:

SpringBoot가 Redis를 통합하여 높은 동시 데이터 캐싱을 달성하는 방법

첫 번째 시간은 3.34초이고 두 번째 시간은 43ms, 효율성은 확실합니다. 개선!

방법 2: SpringBoot 주석을 사용하여 캐싱 활성화

방법 1에 따라

시작 클래스에 @EnableCaching 주석을 추가합니다@EnableCaching注解

SpringBoot가 Redis를 통합하여 높은 동시 데이터 캐싱을 달성하는 방법

修改service层实现类代码
package com.redis.demo.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.redis.demo.constant.RedisConstants;
import com.redis.demo.dao.BladeUserMapper;
import com.redis.demo.entity.BladeUser;
import com.redis.demo.result.DealResult;
import com.redis.demo.service.IBladeUserService;
import com.redis.demo.status.CacheNameStatus;
import com.redis.demo.utils.RedisUtils;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author laz
 * @since 2023-03-09
 */
@Service
public class BladeUserServiceImpl extends ServiceImpl<BladeUserMapper, BladeUser> implements IBladeUserService {
    @Autowired
    private  RedisUtils redisUtils;

//    @Override
//    public DealResult getById(Long id) {
//
//        String userKey = RedisConstants.CACHE_USER_KEY+id;
//        Object user = redisUtils.get(userKey);
//        if (!ObjectUtils.isEmpty(user)){
//
//            return DealResult.data(JSONUtil.toBean(JSONUtil.toJsonStr(user),BladeUser.class));
//        }
//
//        BladeUser bladeUser = baseMapper.selectById(id);
//        redisUtils.set(userKey, JSON.toJSONString(bladeUser));
//        return DealResult.data(bladeUser);
//    }

    @Cacheable(cacheNames = CacheNameStatus.BLADE_USER,keyGenerator = CacheNameStatus.KEY_GENERATOR)
    @Override
    public DealResult getById(Long id) {
        BladeUser bladeUser = baseMapper.selectById(id);
        return DealResult.data(bladeUser);
    }
}
修改RedisConfig配置类

在配置类中添加自定义KeyGenerator

  /**
     * 自定义KeyGenerator
     * @return
     */
    @Bean
    public KeyGenerator simpleKeyGenerator() {
        return (o, method, objects) -> {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(o.getClass().getSimpleName());
            stringBuilder.append(".");
            stringBuilder.append(method.getName());
            stringBuilder.append("[");
            for (Object obj : objects) {
                if(obj.toString().indexOf("Vo@")!= -1)
                {
                    Map<String, Object> map = MapUtil.getAttrFromModel(obj);
                    stringBuilder.append("[");
                    for(String item:map.keySet())
                    {
                        stringBuilder.append(",");
                        stringBuilder.append(map.get(item));
                    }

                    stringBuilder.append(",");
                    stringBuilder.deleteCharAt(stringBuilder.length() - 1);

                    stringBuilder.append("]");

                }
                else {
                    stringBuilder.append(obj);
                    stringBuilder.append(",");
                }

            }

            stringBuilder.append("]");
            return stringBuilder.toString();
        };
    }

:关于 @Cacheable

SpringBoot가 Redis를 통합하여 높은 동시 데이터 캐싱을 달성하는 방법

서비스 계층 구현 클래스 코드 수정

rrreee

RedisConfig 구성 클래스를 수정하세요🎜🎜구성에서 사용자 정의 KeyGenerator🎜rrreee🎜🎜🎜Note🎜🎜를 클래스에 추가하세요. @Cacheable 주석의 매개변수에 관해 이해가 안 되신다면, 클릭해서 볼 수 있습니다. 🎜🎜프로젝트를 다시 시작하고 위 인터페이스에 다시 액세스하여 응답 시간을 관찰합니다. 🎜🎜첫 번째 시간: 🎜

SpringBoot가 Redis를 통합하여 높은 동시 데이터 캐싱을 달성하는 방법

두 번째:

SpringBoot가 Redis를 통합하여 높은 동시 데이터 캐싱을 달성하는 방법

첫 번째는 2.52초이고 두 번째는 44ms로 효율성이 크게 향상된 것을 확인할 수 있습니다.

Redis 시각화 도구를 통해 캐시 데이터를 관찰하세요.

SpringBoot가 Redis를 통합하여 높은 동시 데이터 캐싱을 달성하는 방법

SpringBoot가 Redis를 통합하여 높은 동시 데이터 캐싱을 달성하는 방법

캐시된 데이터의 크기를 관찰하면 첫 번째 방법은 449바이트이고 두 번째 방법은 976바이트임을 알 수 있습니다. 메모리 사용량 측면에서 블로거는 캐싱에 RedisTemplate 방법을 사용한다고 믿습니다. 이 방법은 상대적으로 적은 메모리를 차지하므로 더 적합합니다.

위 내용은 SpringBoot가 Redis를 통합하여 높은 동시 데이터 캐싱을 달성하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제