Spring Boot【定制化】~ 集成Redis实现注解缓存

目录

1、简介

2、整合Redis实现注解缓存

2.1、Redis缓存测试环境搭建

2.2、引入Redis缓存依赖

2.3、yml配置redis连接

2.4、Redis缓存序列化以及自定义缓存管理器配置

2.5、开启注解缓存

2.6、Spring 缓存管理器

2.7、Spring提供的几个重要缓存注解

2.8、@EnableCaching

2.9、@Caacheable

2.10、@CacheEvict

2.11、@CachePut 


1、简介

  • 缓存就是数据交换的缓冲区(Cache),有一些需要经常被访问数据并且比较少更新的数据,就可以缓存起来。当用户查询数据,先从缓存中查找,如果找到了则直接返回,找不到则去数据库中查找。
  • 缓存的本质就是减少数据库IO,减轻服务器压力,减少网络延迟,加快页面打开速度。

2、整合Redis实现注解缓存

2.1、Redis缓存测试环境搭建

1、创建一个 Spring Boot 项目

2、pom 依赖

        <!-- Redis -->
        <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>5.1.47</version>
        </dependency>

        <!-- mybatis-plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <!-- 版本按自己需要选择也可以 -->
            <version>3.5.1</version>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </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>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

3、创建测试数据库

  • 创建 cache_test 数据库
  • 创建测试表和测试数据
  • drop table sys_commodity;
    create table sys_commodity
    (
        `commodity_id` int(11) not null auto_increment primary key,
        `commodity_name` varchar(50),
        `commodity_type` varchar(50),
        `commodity_price` varchar(50),
        `commodity_add_date_time` datetime
    );
    
    # 创建测试数据
    insert into sys_commodity(`commodity_name`, `commodity_type`, `commodity_price`, `commodity_add_date_time`) 
    values
    ('鸭嘴帽', 'A', 29, now()),
    ('小米10手机', 'A', 3999, now()),
    ('苹果', 'A', 8, now()),
    ('鼠标', 'A', 199, now()),
    ('杯子', 'A', 9, now()),
    ('软甲呀', 'A', 999999999, now())
    
    select * from sys_commodity;

4、编写商品URUD

Commodity

/**
 * 商品实体模型(用于缓存测试)
 *
 * @author cms
 * @version 1.0.0.0
 * @Date: 2022/5/24 14:59
 */
@Data
@TableName(value = "sys_commodity")
public class Commodity implements Serializable
{

    /** 商品编号 */
    @TableId(value = "commodity_id", type = IdType.AUTO)
    private Integer commodityId;

    /** 商品名称 */
    @NotBlank(message = "商品名不能为空!")
    @TableField(value = "commodity_name")
    private String commodityName;

    /** 商品类型 */
    @NotBlank(message = "商品类型不能为空!")
    @TableField(value = "commodity_type")
    private String commodityType;

    /** 商品价格 */
    @NotBlank(message = "商品价格不能为空!")
    @TableField(value = "commodity_price")
    private String commodityPrice;

    /** 商品添加时间 */
    @TableField(value = "commodity_add_date_time")
    private Date commodityAddDateTime;

}

ICommodity

/**
 * @author cms
 * @version 1.0.0.0
 * @Date: 2022/5/24 15:25
 */
@Repository
public interface ICommodityMapper extends BaseMapper<Commodity> //使用mybatis-plus快速完成CRUD
{
}

ICommodityService

/**
 * @author cms
 * @version 1.0.0.0
 * @Date: 2022/5/24 15:26
 */
public interface ICommodityService extends IService<Commodity>
{
    /**
     * 添加商品
     * @param commodity 商品实体
     * @return 结果
     */
    Boolean saveCommodity(Commodity commodity);

    /**
     * 删除商品
     * @param commodity 商品实体
     * @return 结果
     */
    Boolean deleteCommodity(Commodity commodity);

    /**
     * 修改商品
     * @param commodity 商品实体
     * @return 结果
     */
    Boolean updateCommodity(Commodity commodity);

    /**
     * 查询商品列表
     * @return 结果
     */
    List<Commodity> queryCommodityList();

    /**
     * 查询商品信息(按ID)
     * @param commodityId 商品ID
     * @return 结果
     */
    Commodity queryByIdCommodity(Integer commodityId);

}

CommodityServiceImpl

/**
 * @author cms
 * @version 1.0.0.0
 * @Date: 2022/5/24 15:29
 */
@Service
public class CommodityServiceImpl extends ServiceImpl<ICommodityMapper, Commodity> implements ICommodityService
{

    @Autowired
    private ICommodityMapper commodityMapper;

    @Override
    public Boolean saveCommodity(Commodity commodity)
    {
        commodity.setCommodityAddDateTime(new Date());
        return commodityMapper.insert(commodity) > 0;
    }

    @Override
    public Boolean deleteCommodity(Commodity commodity)
    {
        return commodityMapper.deleteById(commodity.getCommodityId()) > 0;
    }

    @Override
    public Boolean updateCommodity(Commodity commodity)
    {
        return commodityMapper.updateById(commodity) > 0;
    }

    @Override
    public List<Commodity> queryCommodityList() {
        return commodityMapper.selectList(null);
    }

    @Override
    public Commodity queryByIdCommodity(Integer commodityId)
    {
        return commodityMapper.selectById(commodityId);
    }

}

5、编写 Controller

/**
 * @author cms
 * @version 1.0.0.0
 * @Date: 2022/5/24 16:17
 */
@RestController
@RequestMapping(value = "/commodity")
public class CommodityController
{

    @Autowired
    private ICommodityService commodityService;

    /**
     * 添加商品
     * @param commodity 商品实体
     * @return 添加结果
     */
    @PostMapping
    public Object addCommodity(@RequestBody Commodity commodity)
    {
        return commodityService.saveCommodity(commodity) ? "添加商品成功" : "添加商品失败";
    }

    /**
     * 删除商品
     * @param commodity 商品实体
     * @return 删除结果
     */
    @DeleteMapping
    public Object deleteCommodity(@RequestBody Commodity commodity)
    {
        return commodityService.deleteCommodity(commodity) ? "删除商品成功" : "删除商品失败";
    }

    /**
     * 更新商品信息
     * @param commodity 商品实体
     * @return 更新结果
     */
    @PutMapping
    public Object updateCommodity(@RequestBody Commodity commodity)
    {
        return commodityService.updateCommodity(commodity) ? "更新商品成功" : "更新商品失败";
    }

    /**
     * 查询商品列表
     * @return 商品列表
     */
    @GetMapping(value = "/list")
    public Object listCommodity()
    {
        return commodityService.queryCommodityList();
    }

    /**
     * 查询单个商品
     * @param commodityId 商品编号
     * @return 商品信息
     */
    @GetMapping(value = "/query/{commodityId}")
    public Object getCommodityOne(@PathVariable("commodityId") Integer commodityId)
    {
        return commodityService.queryByIdCommodity(commodityId);
    }

}

6、测试环境是否有问题

环境测试成功 ~ 其他接口自行测试!

2.2、引入Redis缓存依赖

<!-- Redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.3、yml配置redis连接

server:
  port: 8080
# 应用名称
spring:
  application:
    name: springboot-day05-cache
  # mysql
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/cache_test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
    username: root
    password:
  # redis配置
  redis:
    # 地址
    host: localhost
    # 端口号
    port: 6379
    # 密码没有不填
    password:
    # 数据源默认0
    database: 0

# mybatis plus基本配置
mybatis-plus:
  # 配置实体别名
  type-aliases-package: com.ruanjia.entity
  # 配置mapper映射位置
  mapper-locations: classpath*:mappers/**/*Mapper.xml

# 日志配置
logging:
  level:
    com.ruanjia: debug

2.4、Redis缓存序列化以及自定义缓存管理器配置

/**
 * Redis 配置
 *
 * @author cms
 * @version 1.0.0.0
 * @Date: 2022/5/24 18:19
 */
@Configuration
public class RedisConfig extends CachingConfigurerSupport
{

    /**
     * 自定义缓存key生成策略:方法名:参数列表
     * @return
     */
    /*@Override
    public KeyGenerator keyGenerator()
    {
        return new KeyGenerator()
        {
            @Override
            public Object generate(Object target, Method method, Object... params)
            {
                return method.getName() + ":" + Arrays.asList(params);//例如:query:123
            }
        };
    }*/

    /**
     * Redis缓存模板
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate<Object,Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        /* new StringRedisSerializer() */
        redisTemplate.setKeySerializer(stringRedisSerializer());
        redisTemplate.setHashKeySerializer(stringRedisSerializer());
        /* new Jackson2JsonRedisSerializer<>() */
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer());
        return redisTemplate;
    }

    /* key序列化 */
    private RedisSerializer<String> stringRedisSerializer()
    {
        return new StringRedisSerializer();
    }

    /* value序列化 */
    private RedisSerializer<Object> jackson2JsonRedisSerializer()
    {
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        jackson2JsonRedisSerializer.setObjectMapper(mapper);
        return jackson2JsonRedisSerializer;
    }

    /**
     * 使用自定义缓存管理器
     * @param connectionFactory
     * @return
     */
    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory)
    {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofDays(1))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer()))
                .disableCachingNullValues();
        return RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(config)
                .transactionAware()
                .build();
    }

}

2.5、开启注解缓存

开启方法:直接在Spring Boot启动类添加 @EnableCaching 开启注解缓存

@MapperScan("com.ruanjia.mapper")
@EnableCaching //开启注解缓存
@SpringBootApplication
public class SpringbootDay05CacheApplication
{

    public static void main(String[] args)
    {
        SpringApplication.run(SpringbootDay05CacheApplication.class, args);
    }

}

2.6、Spring 缓存管理器

  • 缓存管理器(CacheManager),管理着多个《缓存组件》
  • 每个缓存组件都是唯一,拥有自己唯一的名字

2.7、Spring提供的几个重要缓存注解

  1. @EnableCaching           开启注解缓存
  2. @Caacheable                根据方法请求参数经行结果缓存
  3. @CacheEvict                 清空缓存
  4. @CachePut                    保证方法被调用,又希望被缓存(更新缓存)

2.8、@EnableCaching

作用:开启注解形式缓存

@MapperScan("com.ruanjia.mapper")
@EnableCaching //开启注解缓存
@SpringBootApplication
public class SpringbootDay05CacheApplication
{

    public static void main(String[] args)
    {
        SpringApplication.run(SpringbootDay05CacheApplication.class, args);
    }

}

2.9、@Caacheable

作用:根据方法请求参数进行方法结果缓存(可以指定缓存条件)

/**
     * @Cacheable 符合条件就缓存
     * 注解属性作用:
     *    1、value/cacheName:缓存组件名(可以指定多个缓存)
     *    2、key:缓存数据的key(默认使用方法参数的值)
     *    3、常用的缓存SpEL(使用 # 取值)
     *       获取当前调用方法名:#root.methodName
     *       获取当前被调用的方法:#root.method.name
     *       获取当前被调用目标对象:#root.target
     *       获取当前被调用目标对象类:#root.targetClass
     *       获取被调用方法参数列表:#root.args[0]
     *       获取方法参数的值(可以直接#参数名):#commodityId
     *       获取方法执行后的返回值:#result
     *    4、keyGenerator:指定key生成策略(key/keyGenerator: 只能选择其中一个生效)
     *    5、cacheManager:指定缓存管理器
     *    6、condition:符合条件才经行缓存
     *    7、unless:unless为true就不缓存这个方法
     *
     *
     * @param commodityId 商品ID
     * @return 结果
     */
    @Cacheable(cacheNames = {"commodity"})
    @Override
    public Commodity queryByIdCommodity(Integer commodityId)
    {
        return commodityMapper.selectById(commodityId);
    }

2.10、@CacheEvict

作用:根据缓存的key清除缓存,亦可以清楚指定缓存组件下所有缓存

    /**
     * @CacheEvict:清除缓存
     * allEntries = true:清除指定缓存组件下所有缓存
     * beforeInvocation = true:方法调用前清除缓存
     * cacheNames = {"commodity"}, key = "#commodity.getCommodityId()":更具指定key清除缓存
     * 
     * @param commodity 商品实体
     * @return
     */
    //@CacheEvict(cacheNames = {"commodity"}, allEntries = true, beforeInvocation = true) //清楚指定缓存组件下所有缓存
    @CacheEvict(cacheNames = {"commodity"}, key = "#commodity.getCommodityId()") //根据指定缓存的key清楚缓存
    @Override
    public Boolean deleteCommodity(Commodity commodity)
    {
        return commodityMapper.deleteById(commodity.getCommodityId()) > 0;
    }

2.11、@CachePut 

作用:调用方法,更新指定缓存的数据

注意:如果没有找到指定缓存就会把方法结果缓存为新的缓存

    /**
     * @CachePut 保证方法被调用,同时根据缓存中的key更新缓存数据
     * 注意:如果缓存中没有找到对应的key就会缓存一条新的数据
     *
     * @param commodity 商品实体
     * @return
     */
    @CachePut(cacheNames = {"commodity"}, key = "#commodity.getCommodityId()") // 根据缓存中的key更新缓存,例如:commodity::1
    @Override
    public Commodity updateCommodity(Commodity commodity)
    {
        if (commodityMapper.updateById(commodity) > 0)
        {
            return commodityMapper.selectById(commodity.getCommodityId());
        }
        throw new RuanjiaExceptionHandler(ErrorEnum.S_CATCH_AUTH, "商品更新失败!");
    }

摆烂!不写了 ~ 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值