在项目开发中,经常会碰到一些数据量小、但使用频率极高的数据。比如,团队到BU的映射表。此类数据通常不会变动,使用频率高且数据量较小,如果每次使用都去数据库查询,代价比较大,可以考虑在项目启动时将此类数据加载到缓存中,并定时进行增量更新。
项目中本身没有用redis,也没必要上,java的本地缓存完全可以满足需求。当然,数据量较大的情况下,还是不推荐这样使用的,可能会造成OOM。
下面是一个缓存的抽象类,子类继承并实现toHandler()
方法后,相关数据就会在项目启动时被加载到缓存中,然后通过getEntityById()
方法获取。
java
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);
}
}
下面是一个BaseCache
的子类,功能是将userid和username放入内存进行映射,并提供【根据id获取name】和【根据name获取id】两个get方法。
ps: 实际业务代码肯定不是这种鸡肋的内容啦,数据脱敏。
UserCache
类被@Repository
和@Lazy
注解修饰,在第一次被用到的时候会被注入到IOC容器中,此时会调用其(父类BaseCache)构造函数,开始执行定时任务,调用toHandler()
方法,将数据存入idCacheMap中。
因为业务的需要,既要通过key获取到value,又要通过value获取到key,因此我在这里没有复用父类中的map,而是添加了一个BiMap
。
java
@Lazy
@Repository
public class UserCache extends BaseCache<User>{
// Map<userid, username>
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);
}
}