一、背景
在项目中,在一个接口中,会有很多次重复的查库操作,很是影响性能。
这个时候可以自实现缓存来降低查库操作,提升性能。
二、缓存设计思路:
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