目录
二、Guava Cache/Ehcache/MapDB堆内缓存对比
一、Java缓存类型
类型 | 优点 | 缺点 | 组件 | 适用场景 | 注意 |
堆内缓存 | 速度最快 | 1.受JVM堆大小限制 2.JVM重启时数据消失 | Guava Cache、 Ehcache、 MapDB | 热点数据、 数据量少 | 1.存储软弱引用对象 2.无需序列化/反序列化 |
堆外缓存 | 速度较慢 | 1.受机器内存大小限制 2.机器重启时数据消失 | Ehcache、 MapDB | 相对热的数据 | 需序列化/反序列化 |
磁盘缓存 | 数据不会丢失 | 速度很慢 | Ehcache、 MapDB | 不热的数据 | 需序列化/反序列化 |
分布式缓存 | 大量数据缓存 | 速度最慢 | Redis、 Ehcache + Terracotta | 全量数据 | 1.可单机、可集群 2.需序列化/反序列化 |
二、Guava Cache/Ehcache/MapDB堆内缓存对比
类型 | 描述 | Guava Cache | Ehcache | MapDB |
并发量 | 并发线程数 | .concurrencyLevel | .withDispatcherConcurrency | .concurrencyScale |
条目回收 | 缓存最大条目 | .maximumSize | .heap(100, EntryUnit.ENTRIES) | .expireMaxSize |
TTL回收 | 存活期失效 | .expireAfterWrite(10, TimeUnit.SECONDS) | .withExpiry( ExpiryPolicyBuilder.timeToLiveExpiration( Duration.ofSeconds(10))) | .expireAfterCreate /.expireAfterUpdate |
TTI回收 | 空闲期失效 | .expireAfterAccess(10, TimeUnit.SECONDS) | .withExpiry( ExpiryPolicyBuilder.timeToIdleExpiration( Duration.ofSeconds(10))) | .expireAfterGet |
主动失效 | 主动删除 | .invalidate /.invalidateAll | .remove /.removeAll | .remove /.clear |
触发失效 | 被动删除 | PUT时缓存清理 | PUT时缓存清理 /定义线程池处理 | PUT时缓存清理 /定义线程池处理 |
命中统计 | 缓存命中率 | .recordStats | ------ | ------ |
其他 | 1.Guava Cache只有堆内缓存;定义软弱引用对象:软引用.softValues/弱引用.weakValues; 2.Ehcache提供堆内、堆外、磁盘、分布式缓存,集群功能不完善;若是集群建议Redis; 3.MapDB提供堆内、堆外、磁盘缓存,且提供事务支持; |
三、代码实例
1. 依赖jar包
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1-jre</version>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.mapdb</groupId>
<artifactId>mapdb</artifactId>
<version>3.0.8</version>
</dependency>
2. Cache定义
package com.common.instance.test.config.heapcache;
import com.common.instance.test.dao.WcPendantTabDao;
import com.common.instance.test.entity.WcPendantTab;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.config.builders.ExpiryPolicyBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.units.EntryUnit;
import org.ehcache.spi.loaderwriter.CacheLoaderWriter;
import org.mapdb.DBMaker;
import org.mapdb.HTreeMap;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.Duration;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
* @description 堆内缓存
* @author tcm
* @version 1.0.0
* @date 2021/11/5 17:27
**/
@Component
public class HeapCache {
// Guava Cache缓存
private static LoadingCache<String, List<WcPendantTab>> guavaCache;
// Ehcache Cache缓存
private static Cache<String, List<WcPendantTab>> ehcacheCache;
// MapDB Cache缓存
private static HTreeMap mapDBCache;
// 业务处理
private static WcPendantTabDao wcPendantTabDao;
@Resource
public void setWcPendantTabDao(WcPendantTabDao wcPendantTabDao) {
HeapCache.wcPendantTabDao = wcPendantTabDao;
}
public HeapCache(){
getGuavaCache();
getEhcacheCache();
getMapDBCache();
}
// 初始化Guava Cache缓存
public static LoadingCache<String, List<WcPendantTab>> getGuavaCache(){
if (Objects.isNull(guavaCache)) {
guavaCache = CacheBuilder.newBuilder()
// 并发数量
.concurrencyLevel(4)
// TTL设置
.expireAfterWrite(10, TimeUnit.SECONDS)
// 缓存容量,超出按LRU回收
.maximumSize(10000)
// 软引用,弱引用weakValues
.softValues()
// 缓存统计
.recordStats()
// 缓存没有命中,则读DB
.build(new CacheLoader<String, List<WcPendantTab>>() {
@Override
public List<WcPendantTab> load(String mgdbId) throws Exception {
WcPendantTab tab = new WcPendantTab();
tab.setMgdbId(mgdbId);
return wcPendantTabDao.queryAll(tab);
}
});
}
return guavaCache;
}
// 初始化Ehcache Cache缓存
public static Cache<String, List<WcPendantTab>> getEhcacheCache(){
if (Objects.isNull(ehcacheCache)) {
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build(true);
CacheConfigurationBuilder cacheConfig = CacheConfigurationBuilder
.newCacheConfigurationBuilder(String.class, List.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(100, EntryUnit.ENTRIES)) // 堆内缓存
.withDispatcherConcurrency(4)
// 过期配置
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(10)))
// 缓存没有命中,则读DB
.withLoaderWriter(new CacheLoaderWriter<String, List>() {
@Override
public List load(String mgdbId) throws Exception {
WcPendantTab tab = new WcPendantTab();
tab.setMgdbId(mgdbId);
return wcPendantTabDao.queryAll(tab);
}
@Override
public void write(String s, List list) throws Exception {
}
@Override
public void delete(String s) throws Exception {
}
});
ehcacheCache = cacheManager.createCache("myEhcacheCache", cacheConfig);
}
return ehcacheCache;
}
// 初始化MapDB缓存
public static HTreeMap<String, List<WcPendantTab>> getMapDBCache(){
if (Objects.isNull(mapDBCache)) {
mapDBCache = DBMaker
// 对缓存
.heapDB()
// 并发数
.concurrencyScale(4).make().hashMap("myMapDBCache")
// 最大缓存条目
.expireMaxSize(10000)
// 过期时间
.expireAfterCreate(10, TimeUnit.SECONDS)
.expireAfterUpdate(10, TimeUnit.SECONDS)
.expireAfterGet(10, TimeUnit.SECONDS)
.create();
}
return mapDBCache;
}
}
3. 调用实例
package com.common.instance.test.service.impl;
import com.common.instance.test.config.heapcache.HeapCache;
import com.common.instance.test.dao.WcPendantTabDao;
import com.common.instance.test.entity.WcPendantTab;
import com.common.instance.test.service.WcPendantTabService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
/**
* Tab菜单(WcPendantTab)表服务实现类
*
* @author tcm
* @since 2021-01-14 15:02:08
*/
@Service
public class WcPendantTabServiceImpl implements WcPendantTabService {
@Resource
private WcPendantTabDao wcPendantTabDao;
@Override
public List<WcPendantTab> queryAll(String mgdbId){
List<WcPendantTab> wcPendantTabs = null;
try {
// Cache-As-SoR模式
// 获取Guava Cache缓存的数据
wcPendantTabs = HeapCache.getGuavaCache().get(mgdbId);
// 获取Ehcache Cache缓存的数据
wcPendantTabs = HeapCache.getEhcacheCache().get(mgdbId);
// Cache-Aside模式
// 获取MapDB缓存的数据
wcPendantTabs = HeapCache.getMapDBCache().get(mgdbId);
if (Objects.isNull(wcPendantTabs)) {
WcPendantTab tab = new WcPendantTab();
tab.setMgdbId(mgdbId);
wcPendantTabs = wcPendantTabDao.queryAll(tab);
// 写到缓存
HeapCache.getMapDBCache().put(mgdbId, wcPendantTabs);
}
} catch (ExecutionException e) {
e.printStackTrace();
}
return wcPendantTabs;
}
}
三、参考资料
Guava Cache用法介绍_qianshanding0708的博客-CSDN博客