Local Cache(二)使用与demo

一、使用

1、加local cache

实际使用,可以结合spring cache一起使用。spring cache对于某个key加缓存,local cache再对整个reposrity做缓存,即将spring cache缓存的所有K,V再缓存一次。

2、清除local cache

注意在多模块项目中,如果local cache是公共代码,则需要把各个模块的local cache都执行清除方法。

二、demo

1、pom
<?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>org.example</groupId>
    <artifactId>localcache-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.4</version>
        <relativePath/>
    </parent>


    <dependencies>

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

        <!--尽量不要同时导入mybatis 和 mybatis_plus,避免版本差异-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
            <version>3.5.5</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.13</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

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

        <!--spring cache-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

        <!-- 添加Caffeine Cache依赖 -->
        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
    </dependencies>
</project>
2、util
package com.pluscache.demo.localcache;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

@Slf4j
public class LocalCache<K, V> {

    private final Cache<K, V> cache;
    private final String name;

    public LocalCache(String name, long duration, TimeUnit unit, int maxSize) {
        cache = Caffeine.newBuilder()
                .maximumSize(maxSize)
                .expireAfterWrite(duration, unit)
                .build();
        this.name = name;
        log.info("create one LocalCache: {}", name);
    }

    public V get(K key, CacheLoader<K, V> loader) {
        return cache.get(key, loader::load);
    }

    public V getIfPresent(K key) {
        if (key == null) {
            return null;
        }
        return cache.getIfPresent(key);
    }

    public void put(K key, V value) {
        if (key == null) {
            return;
        }
        cache.put(key, value);
    }

    public void delete(K key) {
        if (key == null) {
            return;
        }
        cache.invalidate(key);
    }

    public void deleteAll() {
        cache.invalidateAll();
    }

    public interface CacheLoader<K, V> {
        V load(K key);
    }
}
3、使用 
package com.pluscache.demo.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pluscache.demo.constructor.UserKeyConstructor;
import com.pluscache.demo.dto.UserDTO;
import com.pluscache.demo.localcache.LocalCache;
import com.pluscache.demo.repository.UserRepository;
import com.pluscache.demo.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

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

@Service("userService")
@Slf4j
public class UserServiceImpl  implements UserService {

    @Autowired
    public UserRepository userRepository;

    //local cache
    public static final LocalCache<String, List<UserDTO>> USER_SERVICE_LOCAL_CACHE =
            new LocalCache<>("userService", 1, TimeUnit.DAYS, 10000);


    @Override
    public List<UserDTO> listUsers() {

        List<UserDTO> listUsers = USER_SERVICE_LOCAL_CACHE.getIfPresent(UserKeyConstructor.listAll());
        if(CollectionUtils.isEmpty(listUsers)){
            listUsers = userRepository.listUsers();
            USER_SERVICE_LOCAL_CACHE.put(UserKeyConstructor.listAll(), listUsers);
            return listUsers;
        }
        log.info("命中local cache缓存");
        return listUsers;
    }

    @Override
    public List<UserDTO> listUsersByAccount(String userAccount) {
        List<UserDTO> listUsers = USER_SERVICE_LOCAL_CACHE.getIfPresent(UserKeyConstructor.listByAccount(userAccount));
        if(CollectionUtils.isEmpty(listUsers)){
            listUsers = userRepository.listUsersByAccount(userAccount);
            USER_SERVICE_LOCAL_CACHE.put(UserKeyConstructor.listByAccount(userAccount), listUsers);
            return listUsers;
        }
        log.info("命中local cache缓存");
        return listUsers;
    }

    @Override
    public UserDTO getById(Integer id) {
        return userRepository.getById(id);
    }

    @Override
    public UserDTO getByIdAndAccount(Integer id, String userAccount) {
        return userRepository.getByIdAndAccount(id,userAccount);
    }

    @Override
    public void saveOrUpdate(UserDTO userDTO) {
        userRepository.saveOrUpdate(userDTO);
    }

    @Override
    public void updateBatch(List<UserDTO> userDTOs) {
        userRepository.updateBatch(userDTOs);
    }

    @Override
    public void deleteById(Integer id) {
        UserDTO userDTO = userRepository.getById(id);
        if (userDTO != null){
            userRepository.deleteById(userDTO,id);
        }
    }

    @Override
    public void deleteByIds(List<Integer> ids) {
        List<UserDTO> userDTOs = userRepository.listByIds(ids);
        if(CollectionUtils.isEmpty(userDTOs)){
            return;
        }
        userRepository.deleteByIds(userDTOs,ids);
    }
}
4、dao
package com.pluscache.demo.repository;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.pluscache.demo.dto.UserDTO;
import com.pluscache.demo.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Repository;

import java.util.List;
@Repository
@CacheConfig(cacheNames = "t_user")
public class UserRepository {

    @Autowired
    private UserMapper userMapper;

    @Cacheable(key = "@userKeyConstructor.listAll()",
            unless = "@userKeyConstructor.checkCacheSize(#result)")
    public List<UserDTO> listUsers() {
        LambdaQueryWrapper<UserDTO> queryWrapper = new LambdaQueryWrapper<>();
        return userMapper.selectList(queryWrapper);
    }

    @Cacheable(key = "@userKeyConstructor.listByAccount(#userAccount)",
            unless = "@userKeyConstructor.checkCacheSize(#result)")
    public List<UserDTO> listUsersByAccount(String userAccount) {
        LambdaQueryWrapper<UserDTO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserDTO::getUserAccount,userAccount);
        return userMapper.selectList(queryWrapper);
    }


    @Cacheable(key = "@userKeyConstructor.getById(#id)",
            unless = "@userKeyConstructor.checkCacheSize(#result)")
    public UserDTO getById(Integer id) {
        LambdaQueryWrapper<UserDTO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserDTO::getId,id);
        return userMapper.selectOne(queryWrapper);
    }

    @Cacheable(key = "@userKeyConstructor.getByIdAccount(#id,#userAccount)",
            unless = "@userKeyConstructor.checkCacheSize(#result)")
    public UserDTO getByIdAndAccount(Integer id, String userAccount) {
        LambdaQueryWrapper<UserDTO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserDTO::getUserAccount,userAccount);
        queryWrapper.eq(UserDTO::getId,id);
        return userMapper.selectOne(queryWrapper);
    }

    public List<UserDTO> listByIds(List<Integer> ids) {
        LambdaQueryWrapper<UserDTO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(UserDTO::getId,ids);
        return userMapper.selectList(queryWrapper);
    }

    @CacheEvict(key = "@userKeyConstructor.getAllKeys(#userDTO)")
    public void saveOrUpdate(UserDTO userDTO) {
        if(userDTO.getId() != null){
            userMapper.updateById(userDTO);
            return;
        }
        userMapper.insert(userDTO);
    }

    @CacheEvict(key = "@userKeyConstructor.getAllKeys(#userDTOs)")
    public void updateBatch(List<UserDTO> userDTOs) {
        userMapper.updateBatch(userDTOs);
    }

    @CacheEvict(key = "@userKeyConstructor.getAllKeys(#userDTO)")
    public void deleteById(UserDTO userDTO, Integer id) {
        userMapper.deleteById(id);
    }


    @CacheEvict(key = "@userKeyConstructor.getAllKeys(#userDTOs)")
    public void deleteByIds(List<UserDTO> userDTOs, List<Integer> ids) {
        userMapper.deleteBatchIds(ids);
    }
}
5、测试

(1)

① 第一次访问localhost:7777/cacheDemo/user/listUsers从数据库查询

② 再次访问,先命中local cache缓存

2024-07-17T17:10:01.817+08:00  INFO 65088 --- [nio-7777-exec-3] c.p.demo.service.impl.UserServiceImpl    : 命中local cache缓存

(2)

① 第一次访问localhost:7777/cacheDemo/user/listByAccount?userAccount=zs从数据库查询

JDBC Connection [HikariProxyConnection@1475868044 wrapping com.mysql.cj.jdbc.ConnectionImpl@33d4cbb8] will not be managed by Spring
==>  Preparing: SELECT id,user_name,user_account,age FROM t_user WHERE (user_account = ?)
==> Parameters: zs(String)
<==    Columns: id, user_name, user_account, age
<==        Row: 1, testzs, zs, 18
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@62bdbace]

②  再次访问,命中local cache缓存

2024-07-17T18:05:35.383+08:00  INFO 65088 --- [nio-7777-exec-8] c.p.demo.service.impl.UserServiceImpl    : 命中local cache缓存

(3)重启项目

local cache失效,走的spring cache。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

w_t_y_y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值