• Java本地缓存的使用


    项目开发中,经常会碰到一些数据量小、但使用频率极高的数据。比如,团队到BU的映射表。此类数据通常不会变动,使用频率高且数据量较小,如果每次使用都去数据库查询,代价比较大,可以考虑在项目启动时将此类数据加载到缓存中,并定时进行增量更新

    项目中本身没有用redis,也没必要上,java的本地缓存完全可以满足需求。当然,数据量较大的情况下,还是不推荐这样使用的,可能会造成OOM。

    下面是一个缓存的抽象类,子类继承并实现toHandler()方法后,相关数据就会在项目启动时被加载到缓存中,然后通过getEntityById()方法获取。

    public abstract class BaseCache<T> {
        // 用于定时执行更新任务
        ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor();
        // map存储数据
        Map<Object, T> cacheMap = new HashMap<>();
        BaseMapper<T> baseDao;
        // 用于记录上一次缓存更新的时间
        protected Date currentTime = DateUtil.getDate(2000, 1, 1);
    
        public BaseCache() {
            this.baseDao = baseDao;
    
            //定时获取缓存
            timer.scheduleAtFixedRate(() -> {
                List<T> results = getList();
                if (results.size() > 0) {
                    T result = results.get(results.size() - 1);
                    if (result instanceof Map) {
                        currentTime = (Date) ((Map) result).get("DataChange_LastTime");
                    } else {
                        currentTime = (Date) ReflectionUtils.getFieldValue(result, "datachangeLasttime");
                    }
                    toHandler(results);
                }
    
            }, 1000, 1000, TimeUnit.MILLISECONDS);   // 时间可以根据业务需要进行变更
        }
    
        // 根据数据变更时间,获取增量数据
        protected List<T> getList() {
            QueryWrapper<T> queryWrapper = new QueryWrapper<>();
            queryWrapper.gt("DataChange_LastTime", currentTime);
            queryWrapper.orderByAsc("DataChange_LastTime");
            return baseDao.selectList(queryWrapper);
        }
    
        // 此抽象方法由子类实现,往缓存中(cacheMap)存放所需要的值
        protected abstract void toHandler(List<T> results);
    
        // 从缓存中获取数据
        public T getEntityById(Object id) {
            return cacheMap.get(id);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    下面是一个BaseCache的子类,功能是将userid和username放入内存进行映射,并提供【根据id获取name】和【根据name获取id】两个get方法。

    ps: 实际业务代码肯定不是这种鸡肋的内容啦,数据脱敏。

    UserCache类被@Repository@Lazy注解修饰,在第一次被用到的时候会被注入到IOC容器中,此时会调用其(父类BaseCache)构造函数,开始执行定时任务,调用toHandler()方法,将数据存入idCacheMap中。

    因为业务的需要,既要通过key获取到value,又要通过value获取到key,因此我在这里没有复用父类中的map,而是添加了一个BiMap

    @Lazy
    @Repository
    public class UserCache extends BaseCache<User>{
    
        // Map
        private BiMap<Long, String> idCacheMap = HashBiMap.create();
    
        @Autowired
        public void setDao(UserDao entityDao) {
            this.baseDao = entityDao;
        }
    
        @Override
        protected void toHandler(List<User> results) {
            results.stream().forEach(p -> {
                this.idCacheMap.put(p.getUserid(), p.getUserName());
            });
        }
    
        public Long getUsername(Long userid) {
            return idCacheMap.get(userid);
        }
    
        public Long getUserid(String username) {
            return idCacheMap.inverse().get(username);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
  • 相关阅读:
    网络协议--Traceroute程序
    PAT 1013 Battle Over Cities
    在3D视觉技术的帮助下,轻松实现纸箱拆码垛
    非关系型数据库(NoSQL)——redis
    k8s 1.28版本二进制安装
    Unity游戏开发基础之数据结构部分
    PCI认证:为什么它对你的业务至关重要,以及如何成功获得认证?
    算法设计与分析算法实现——棋盘覆盖问题
    1.7-32:行程长度编码
    Git企业开发级讲解(五)
  • 原文地址:https://blog.csdn.net/knock_me/article/details/133881908