目录
什么是缓存
为什么要用缓存
Redis为什么这么快
实现一个用户信息的缓存
方式一:利用RedisTemplate实现 导入依赖
添加配置
添加redis工具类及配置类
service层
controller层
测试
方式二:采用SpringBoot注解开启缓存
修改service层实现类代码
修改RedisConfig配置类
首页 数据库 Redis SpringBoot怎么整合Redis实现高并发数据缓存

SpringBoot怎么整合Redis实现高并发数据缓存

May 27, 2023 pm 09:24 PM
redis springboot

什么是缓存

缓存是⼀个高速数据交换的存储器,使用它可以快速的访问和操作数据。

举个通俗的例子。

小明经营着一家饭店,在刚开张的时候由于名气不足,客源少,生意并不是很忙,平时没事的时候就闲着,有客人来了再进厨房安排做菜。随着饭店的日益发展,此时的饭店已经不同往日,有着大量的稳定客源,并且在某些节假日的时候甚至爆满。按照以前的做法,那肯定是行不通了,在用餐高峰期的时候因为备餐慢导致了客户的长时间等待,使得饭店的屡遭投诉。
为解决这一问题,小明想到了一个办法,可以在空闲的时候,提前将热门的菜做完后放入保温柜,等用餐高峰期时再拿出来加热后就可以直接上菜,就规避了短时间内大量客源而导致的备餐慢的问题,通过这一方法,即使在高峰期,也能很好的应对。

缓存的核心是将经常被访问的资源(高频读、低频写)预先存储在最接近用户且访问速度更快的位置,以提升访问速度。

为什么要用缓存

使用缓存后,效率会大大的提升,减少了不必要的资源消耗,提升了用户体验。

redis的特点:

  • redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加在进行使用。

  • redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的储存

  • redis支持数据的备份,即master-slave模式的数据备份

redis的优势:

  • 性能极高——redis能读得的速度是110000次/s,写的速度是81000次/s。

  • 丰富的数据类型——redis支持二进制案例的Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。

  • 原子——redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过multi和exec指令包起来。

  • 丰富的特性redis还支持publish/subscribe,通知,key过期等等特性

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='用户表';
登录后复制

方式一:利用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
登录后复制
添加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);
    }
}
登录后复制

开发mapper接口

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层

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层
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);
    }

}
登录后复制
测试

启动项目,使用postman访问该接口,连续请求两次,观察响应时长:

第一次:

SpringBoot怎么整合Redis实现高并发数据缓存

第二次:

SpringBoot怎么整合Redis实现高并发数据缓存

可以看到,第一次3.34s,第二次43ms,效率明显提高!

方式二:采用SpringBoot注解开启缓存

以方式一为准

在启动类添加@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实现高并发数据缓存

第二次:

SpringBoot怎么整合Redis实现高并发数据缓存

可以看到,第一次2.52s,第二次44ms,效率明显提高!

通过Redis可视化工具观察缓存数据:

SpringBoot怎么整合Redis实现高并发数据缓存

SpringBoot怎么整合Redis实现高并发数据缓存

通过观察缓存数据大小可知:方式一449字节,方式二976字节,如果从内存占用大小的角度考虑,博主认为使用RedisTemplate方式做缓存更合适,因为这种方式所占内存相对较少。

以上是SpringBoot怎么整合Redis实现高并发数据缓存的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

redis集群是如何实现的 redis集群是如何实现的 Apr 10, 2025 pm 05:27 PM

Redis集群是一种分布式部署模式,允许水平扩展Redis实例,通过节点间通信、哈希槽划分键空间、节点选举、主从复制和命令重定向来实现:节点间通信:通过集群总线实现虚拟网络通信。哈希槽:将键空间划分为哈希槽,确定负责键的节点。节点选举:至少需要三个主节点,通过选举机制确保仅有一个活动主节点。主从复制:主节点负责写请求,从节点负责读请求和数据复制。命令重定向:客户端连接到负责键的节点,节点重定向不正确的请求。故障处理:故障检测、标记下线和重新

redis查询的key怎么唯一 redis查询的key怎么唯一 Apr 10, 2025 pm 07:03 PM

Redis采用五种策略确保键的唯一性:1. 名称空间分隔;2. HASH数据结构;3. SET数据结构;4. 字符串键的特殊字符;5. Lua脚本验证。具体策略的选择取决于数据组织、性能和扩展性需求。

redis事务如何处理 redis事务如何处理 Apr 10, 2025 pm 05:24 PM

Redis 事务确保原子性、一致性、隔离性和持久性(ACID)属性,其运作方式如下:启动事务:使用 MULTI 命令。记录命令:执行任意数量的 Redis 命令。提交或回滚事务:使用 EXEC 命令提交事务,或 DISCARD 命令回滚事务。提交:若无错误,EXEC 命令提交事务,所有命令原子地应用到数据库。回滚:若有错误,DISCARD 命令回滚事务,所有命令被丢弃,数据库状态保持不变。

redis怎么查看所有的key redis怎么查看所有的key Apr 10, 2025 pm 07:15 PM

要查看 Redis 中的所有键,共有三种方法:使用 KEYS 命令返回所有匹配指定模式的键;使用 SCAN 命令迭代键并返回一组键;使用 INFO 命令获取键的总数。

redis底层怎么实现 redis底层怎么实现 Apr 10, 2025 pm 07:21 PM

Redis 使用哈希表存储数据,支持字符串、列表、哈希表、集合和有序集合等数据结构。Redis 通过快照 (RDB) 和追加只写 (AOF) 机制持久化数据。Redis 使用主从复制来提高数据可用性。Redis 使用单线程事件循环处理连接和命令,保证数据原子性和一致性。Redis 为键设置过期时间,并使用 lazy 删除机制删除过期键。

redis zset怎么使用 redis zset怎么使用 Apr 10, 2025 pm 07:27 PM

Redis 有序集合(ZSet)用于存储有序元素集合,并按关联分数进行排序。ZSet 的用法步骤包括:1. 创建 ZSet;2. 添加成员;3. 获取成员分数;4. 获取排名;5. 获取排名范围的成员;6. 删除成员;7. 获取元素个数;8. 获取分数范围内的成员个数。

redis如何查看版本号 redis如何查看版本号 Apr 10, 2025 pm 05:57 PM

要查看 Redis 版本号,可以使用以下三种方法:(1) 输入 INFO 命令,(2) 使用 --version 选项启动服务器,(3) 查看配置文件。

redis如何做内存优化 redis如何做内存优化 Apr 10, 2025 pm 06:24 PM

为了优化 Redis 内存使用,可以采取以下措施:使用合适的数据结构,例如散列表、列表、压缩列表或哈希表。启用压缩功能以压缩重复数据。使用对象共享来存储相似的对象。限制键的数量并使用哈希标签对相关键进行分组。删除过期键并使用持久化来防止数据丢失。使用 RDB 或 AOF 作为持久化方式,监控内存使用情况并使用 Redis 内存服务器。使用空间效率高的数据结构、禁用惰性过期功能并控制 zset 中的压缩列表条目数。

See all articles