1. Fundo
Em um projeto, em uma interface, haverá muitas operações repetidas de verificação de banco de dados, o que afeta muito o desempenho.
Neste momento, você mesmo pode implementar o cache para reduzir as operações de verificação do banco de dados e melhorar o desempenho.
2. Ideias de design de cache:
1. O cache precisa fornecer uma função de armazenamento; um cache precisa de um contêiner para armazenar os dados em cache; geralmente escolha Map, considerando a simultaneidade, geralmente use ConcurrentHashMap; 2. O cache precisa fornecer uma interface para obter dados;
ao consultar dados, você pode chamar essa interface diretamente de Obter dados do cache para evitar pesquisas no banco de dados;
3. O cache precisa fornecer uma interface para adicionar dados; na interface de negócios, se novos dados forem adicionados, essa interface pode ser chamada para armazenar em cache os novos dados;
4. O cache precisa fornecer uma interface para exclusão de dados; na interface de negócios Na interface, se os dados forem modificados ou excluídos, esta interface pode ser chamada para excluir os dados armazenados em cache; 5. O cache precisa fornecer
um interface de atualização de dados; na interface de negócios, se os dados forem modificados, esta interface pode ser chamada para atualizar os dados armazenados em cache; 6. O cache precisa
fornecer uma interface de atualização de dados em lote; quando o sistema é iniciado, esta interface pode ser chamada para carregar dados no cache em lotes;
3. Realização
1.Interface de cache
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. Implementação de abstração de cache
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. Implementação de cache real
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);
}
}
}
4. Endereço do projeto
Endereço do anfitrião: https://gitee.com/AiWanDeXiaoCaiNiao/nobiz/tree/master/cache