🧃SpringBoot整合Caffeine(注解方式)

一、了解缓存配置

  先来了解一下配置方法吧,SimpleCacheManager和CaffeineCacheManager配置的区别:

SimpleCacheManager:
    这种缓存管理器允许你在应用程序启动时通过配置多个CaffeineCache来创建多个缓存。
    这种方式可以让你为每个方法单独配置缓存过期时间。
CaffeineCacheManager:
    这种缓存管理器使用了一个全局的Caffeine配置来创建所有的缓存。
    这种方式不能为每个方法单独配置缓存过期时间,但是可以在程序启动时配置全局的缓存配置,这样就可以轻松地设置所有方法的缓存过期时间。
总结:
    如果你希望为每个方法单独配置缓存过期时间,那么建议使用第一种方式。
    否则,如果你希望设置全局的缓存配置,那么建议使用第二种方式。

  本文使用MP进行构建,Gitee地址:https://gitee.com/zhang-zhixi/springboot-caffeine.git

二、使用缓存:SimpleCacheManager方式

实体类:User

package com.zhixi.pojo;

import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;

import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * @TableName user
 */
@TableName(value =  "user" )
@Data
public class User implements Serializable {
    /**
     * 主键ID
     */
    @TableId(value =  "id" , type = IdType.AUTO)
    private Long id;
    /**
     * 用户名
     */
    @TableField(value =  "username" )
    private String username;

    /**
     * 密码
     */
    @TableField(value =  "password" )
    private String password;

    /**
     * 姓名
     */
    @TableField(value =  "name" )
    private String name;

    /**
     * 年龄
     */
    @TableField(value =  "age" )
    private Integer age;

    /**
     * 邮箱
     */
    @TableField(value =  "email" )
    private String email;

    /**
     * 版本号,用于乐观锁
     */
    @TableField(value =  "version" )
    private Integer version;

    /**
     * 创建时间
     */
    @TableField(value =  "create_time" , fill = FieldFill.INSERT)
    @JsonDeserialize( using = LocalDateTimeDeserializer. class )
    @JsonSerialize( using = LocalDateTimeSerializer. class )
    // 对入参进行格式化
    @JsonFormat(pattern =  "yyyy-MM-dd HH:mm:ss" , timezone =  "GMT+8" )
    // 对出参进行格式化
    @DateTimeFormat(pattern =  "yyyy-MM-dd HH:mm:ss" )
    private LocalDateTime createTime;


    /**
     * 更新时间
     */
    @TableField(value =  "update_time" , fill = FieldFill.UPDATE)
    @JsonDeserialize( using = LocalDateTimeDeserializer. class )
    @JsonSerialize( using = LocalDateTimeSerializer. class )
    @JsonFormat(pattern =  "yyyy-MM-dd HH:mm:ss" , timezone =  "GMT+8" )
    @DateTimeFormat(pattern =  "yyyy-MM-dd HH:mm:ss" )
    private LocalDateTime updateTime;

    /**
     * 删除状态,0表示未删除,1表示已删除
     */
    @TableField(value =  "deleted" )
    private Integer deleted;

    /**
     * 创建时间,使用MyBatis Plus自动填充功能
     */
    @TableField(value =  "create_at" , fill = FieldFill.INSERT)
    private String createAt;

    /**
     * 更新时间,使用MyBatis Plus自动填充功能
     */
    @TableField(value =  "update_at" , fill = FieldFill.UPDATE)
    private String updateAt;


    @TableField(exist =  false )
    private static final  long serialVersionUID = 1L;
}

CacheNameTimeConstant:定义缓存的过期时间

/**
 * @ClassName CacheNameTimeConstant
 * @Author zhangzhixi
 * @Description 定义键的过期时间
 * @Date 2023-01-05 22:30
 * @Version 1.0
 */
public interface CacheNameTimeConstant {
    String CACHE_DEFAULT =  "CACHE_DEFAULT" ;
    String CACHE_5SECS =  "CACHE_5SECS" ;
    String CACHE_10SECS =  "CACHE_10SECS" ;
    String CACHE_30SECS =  "CACHE_30SECS" ;
}

CaffeineConfig:缓存配置

import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author zhixi
 */
@Configuration
@EnableCaching
public class CaffeineConfig {

    @Bean
    public CacheManager caffeineCacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        List<CaffeineCache> caches = new ArrayList<>();
        caches.add(new CaffeineCache(CacheNameTimeConstant.CACHE_5SECS,
                Caffeine.newBuilder().expireAfterWrite(5, TimeUnit.SECONDS).build()));
        caches.add(new CaffeineCache(CacheNameTimeConstant.CACHE_10SECS,
                Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.SECONDS).build()));
        caches.add(new CaffeineCache(CacheNameTimeConstant.CACHE_30SECS,
                Caffeine.newBuilder().expireAfterWrite(30, TimeUnit.SECONDS).build()));
        cacheManager.setCaches(caches);
        return cacheManager;
    }
}

Service层

UserService

/**
* @author zhangzhixi
* @description 针对表【user】的数据库操作Service
* @createDate 2022-05-01 12:15:07
*/
public interface UserService extends IService {

    /**
     * 根据id查询用户
     *
     * @param userId 用户id
     * @return 用户信息
     */
    User selectByIdUser(Long userId);
    /**
     * 更新用户
     * @param user 实体
     * @return =1更新成功,否则更新失败
     */
    User updateUser(User user);

    /**
     * 删除用户
     * @param userId 用户id
     * @return =1删除成功,否则删除失败
     */
    boolean delUser(Long userId);
}

UserServiceImpl

注解的参数包括:

  • cacheNames:指定缓存的名称。
  • key:指定缓存的 key。这里的 key 是一个 SpEL 表达式,表示使用方法的参数 userId 作为 key。
  • unless:指定当方法的返回值为 null 时,不将结果缓存。

  unless这个注解的作用是,当调用这个方法时,会先在本地缓存中查找是否已经缓存了结果,如果有,则直接返回缓存中的结果;

  如果没有,则执行方法体,并将方法的返回值缓存到本地缓存中,供下次使用。如果方法的返回值为 null,则不会将结果缓存。

package com.zhixi.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhixi.config.CacheNameTimeConstant;
import com.zhixi.mapper.UserMapper;
import com.zhixi.pojo.User;
import com.zhixi.service.UserService;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @author zhangzhixi
 * @description 针对表【user】的数据库操作Service实现
 * @createDate 2022-05-01 12:15:07
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {

    @Resource
    private UserMapper userMapper;

    /**
     * 添加缓存
     */
    @Override
    @Cacheable(key = "#userId", value = CacheNameTimeConstant.CACHE_10SECS, unless = "#result==null")
    public User selectByIdUser(Long userId) {
        return userMapper.selectById(userId);
    }

    /**
     * 更新缓存
     */
    @Override
    @CachePut(key = "#user.id", value = CacheNameTimeConstant.CACHE_10SECS, unless = "#result==null")
    public User updateUser(User user) {
        return userMapper.updateById(user) == 1 ? user : null;
    }

    /**
     * 删除缓存
     */
    @Override
    @CacheEvict(key = "#userId", value = CacheNameTimeConstant.CACHE_10SECS)
    public boolean delUser(Long userId) {
        return userMapper.deleteById(userId) == 1;
    }
}

Controller层

import com.zhixi.pojo.User;
import com.zhixi.service.UserService;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

/**
 * @ClassName UserController
 * @Author zhangzhixi
 * @Description
 * @Date 2022-5-1 12:15
 * @Version 1.0
 */
@RestController
@RequestMapping( "/user" )
public class UserController {

    /**
     * 日志
     */
    private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(UserController. class );

    @Resource
    private UserService userService;

    @RequestMapping( "/getUserById/{id}" )
    public User getUserById(@PathVariable( "id" ) Long id) {
        User user =  new User();
        User queryUser = userService.selectByIdUser(id);
        if (queryUser !=  null ) {
            user = queryUser;
        }
        return user;
    }

    @PostMapping( "/updateUser" )
    public String updatetUser(@RequestBody User user) {
        return userService.updateUser(user) !=  null ?  "更新成功" :  "更新失败" ;
    }

    @PostMapping( "/deleteUser/{id}" )
    public String deleteUser(@PathVariable( "id" ) Long id) {
        return userService.delUser(id) ?  "删除成功" :  "删除失败" ;
    }
}

然后使用postman进行测试即可:

  简单来说就是查询和更新操作会将DB查询的数据放到内存缓存中,下次如果是同样的请求过来,那么就会将此数据直接从内存中返回。

如果删除了缓存,那么下次再执行get操作,就需要重新从DB中去查询

三、使用缓存:CaffeineCacheManager方式

  可以发现,代码的变化并不大,无非是配置文件中创建CacheManager的方式不一样了,还有使用注解上面有一些小差异,要手动指定使用的缓存名称。

CaffeineConfig:缓存配置

package com.zhixi.config;

import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author zhixi
 */
@Configuration
@EnableCaching
public class CaffeineConfig {

    @Bean
    public CacheManager localEntityCacheManager() {
        CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager();
        Caffeine<Object, Object> caffeine = Caffeine.newBuilder()
                // 初始大小
                .initialCapacity(10)
                // 最大容量
                .maximumSize(100)
                // 打开统计
                .recordStats()
                // 5分钟不访问自动丢弃
                .expireAfterAccess(5, TimeUnit.MINUTES);
        caffeineCacheManager.setCaffeine(caffeine);
        // 设定缓存器名称
        caffeineCacheManager.setCacheNames(getNames());
        // 值不可为空
        caffeineCacheManager.setAllowNullValues(false);
        return caffeineCacheManager;
    }

    private static List<String> getNames() {
        List<String> names = new ArrayList<>(1);
        names.add("localEntityCache");
        return names;
    }
}

Service层

UserServiceImpl

package com.zhixi.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhixi.mapper.UserMapper;
import com.zhixi.pojo.User;
import com.zhixi.service.UserService;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @author zhangzhixi
 * @description 针对表【user】的数据库操作Service实现
 * @createDate 2022-05-01 12:15:07
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {

    @Resource
    private UserMapper userMapper;

    /**
     * 添加缓存
     */
    @Override
    @Cacheable(cacheNames = "localEntityCache", key = "#userId",unless = "#result==null")
    public User selectByIdUser(Long userId) {
        return userMapper.selectById(userId);
    }

    /**
     * 更新缓存
     */
    @Override
    @CachePut(cacheNames = "localEntityCache", key = "#user.id",unless = "#result==null")
    public User updateUser(User user) {
        return userMapper.updateById(user) == 1 ? user : null;
    }

    /**
     * 删除缓存
     */
    @Override
    @CacheEvict(cacheNames = "localEntityCache", key = "#userId")
    public boolean delUser(Long userId) {
        return userMapper.deleteById(userId) == 1;
    }
}

 

posted @ 2023-01-06 00:27  Java小白的搬砖路  阅读(1984)  评论(0编辑  收藏  举报