缓存简单实现

一、背景

在项目中,在一个接口中,会有很多次重复的查库操作,很是影响性能。
这个时候可以自实现缓存来降低查库操作,提升性能。

二、缓存设计思路:

1.缓存需要提供存储功能;一个缓存,需要一个容器来存放缓存数据;一般选择 Map,考虑并发,一般使用 ConcurrentHashMap;
2.缓存需要提供获取数据接口;在数据查询时,可以调用该接口直接从缓存中获取数据,避免查库;
3.缓存需要提供添加数据接口;在业务接口中,如果新增了数据,可以调用该接口对新数据进行缓存;
4.缓存需要提供删除数据接口;在业务接口中,如果修改或删除了数据,可以调用该接口对缓存数据进行删除;
5.缓存需要提供刷新数据接口;在业务接口中,如果修改了数据,可以调用该接口对缓存数据进行刷新;
6.缓存需要提供批量刷新数据接口;在系统启动的时候,可以调用该接口批量加载数据到缓存;

三、实现

1.缓存接口


import java.util.List;

/**
 * 缓存应用服务接口。
 *
 * @param <K> 缓存 key。
 * @param <T> 缓存 value。
 */
public interface CacheService<K, T> {
    
    

    /**
     * 缓存最大个数常量。
     */
    public static final int CACHE_MAX_SIZE = 1000;

    /**
     * 添加缓存数据。
     *
     * @param key 缓存 key。
     * @param value 缓存 value。
     */
    void putData(K key, T value);

    /**
     * 获取缓存数据。(单条)
     *
     * @param key 缓存 key。
     */
    T getData(K key);

    /**
     * 获取缓存数据。(批量)
     *
     * @param ids
     * @return
     */
    List<T> getDataBy(List<K> ids);

    /**
     * 删除缓存数据。(单条)
     *
     * @param key 缓存 key。
     */
    void removeDate(K key);

    /**
     * 删除缓存数据。(批量)
     *
     * @param keys 缓存 key 列表。
     */
    void removeBy(List<K> keys);

    /**
     * 清空缓存数据。
     */
    void removeAll();

    /**
     * 刷新缓存数据。(单条)
     *
     * @param key 缓存 key。
     */
    void refreshDataBy(K key);

    /**
     * 加载缓存数据。(批量)(启动时)
     */
    void refreshAll();
}

2.缓存抽象实现


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

public abstract class AbstractCacheService<K, T> implements CacheService<K, T> {
    
    

    public abstract T getDataFromDB(K key);

    public abstract ConcurrentHashMap<K, T> getCacheContainer();

    /**
     * 从缓存获取数据。默认直接从缓存中获取返回。
     *
     * @param key key。
     * @return 缓存数据。
     */
    public T getDataFromCache(K key) {
    
    
        return getCacheContainer().get(key);
    }

    @Override
    public void putData(K key, T value) {
    
    
        if (getCacheContainer() == null) {
    
    
            return;
        }
        if (getCacheContainer().size() >= CACHE_MAX_SIZE) {
    
    
            long index = (long) (Math.random() * CACHE_MAX_SIZE);
            getCacheContainer().remove(index);
        }
        getCacheContainer().put(key, value);
    }

    @Override
    public T getData(K key) {
    
    
        if (getCacheContainer() == null) {
    
    
            return null;
        }
        if (getCacheContainer().get(key) != null) {
    
    
            return getDataFromCache(key);
        }
        T value = this.getDataFromDB(key);
        if (getCacheContainer().size() >= CACHE_MAX_SIZE) {
    
    
            long index = (long) (Math.random() * CACHE_MAX_SIZE);
            getCacheContainer().remove(index);
        }
        if (key != null && value != null) {
    
    
            getCacheContainer().put(key, value);
        }
        return value;
    }

    @Override
    public void removeDate(K key) {
    
    
        if (getCacheContainer() == null) {
    
    
            return;
        }
        if (getCacheContainer().get(key) != null) {
    
    
            getCacheContainer().remove(key);
        }
    }

    @Override
    public void refreshDataBy(K key) {
    
    
        if (getCacheContainer() == null) {
    
    
            return;
        }
        if (getCacheContainer().contains(key)) {
    
    
            getCacheContainer().remove(key);
        }
        getData(key);
    }

    @Override
    public List<T> getDataBy(List<K> ids) {
    
    
        if (getCacheContainer() == null) {
    
    
            return new ArrayList<>();
        }

        List<T> result = new ArrayList<>();
        for (K key : ids) {
    
    
            T data = getData(key);
            result.add(data);
        }
        return result;
    }

    @Override
    public void removeAll() {
    
    
        if (getCacheContainer() == null) {
    
    
            return;
        }
        getCacheContainer().clear();
    }

    @Override
    public void removeBy(List<K> keys) {
    
    
        if (getCacheContainer() == null || keys == null) {
    
    
            return;
        }
        for (K key : keys) {
    
    
            if (getCacheContainer().get(key) != null) {
    
    
                getCacheContainer().remove(key);
            }
        }
    }
}

3.真实缓存实现


import com.example.cache.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 用户缓存服务实现。
 */
@Service
public class UserCacheServiceImpl extends AbstractCacheService<Long, User> {
    
    

    /** 保存 CACHE_MAX_SIZE 个 key 为 K 类型, value 为 T 类型的数据. */
    private static ConcurrentHashMap<Long, User> userCacheData = new ConcurrentHashMap<>(CACHE_MAX_SIZE);

    /** 用户应用层接口。 */
    @Autowired
    @Lazy
    private UserService userService;

    /** 初始化。 */
    @PostConstruct
    public void init() {
    
    
        refreshAll();
    }

    @Override
    public User getDataFromDB(Long key) {
    
    
        return userService.find(key);
    }

    @Override
    public User getDataFromCache(Long key) {
    
    
        return super.getDataFromCache(key);
    }

    @Override
    public ConcurrentHashMap<Long, User> getCacheContainer() {
    
    
        return userCacheData;
    }

    @Override
    public void refreshAll() {
    
    
        // 加载组件信息
        Page<User> users = userService.findAll(Pageable.ofSize(CACHE_MAX_SIZE));
        for (User user : users) {
    
    
            userCacheData.put(user.getId(), user);
        }
    }
}

四、项目地址

Gitee 地址:https://gitee.com/AiWanDeXiaoCaiNiao/nobiz/tree/master/cache

猜你喜欢

转载自blog.csdn.net/weixin_39651041/article/details/129810351
今日推荐