java的本地缓存在工作后一个接一个地被使用,一直想写,一直拿不出手。 最近又关于这方面的问题进行了整理。 独有结构单例、guava、ehcache基本涵盖了目前的大部分行为。
为什么需要本地缓存?
一些系统经常访问的数据,即使数据量很少。 例如,国家标准行政区域数据)。 在这种情况下,必须将数据放在APP应用程序的本地缓存中,以提高系统访问效率并减少不必要的数据库访问。 虽然数据库访问占用数据库连接并占用大量网络,但需要注意的是缓存占用空间和缓存禁用策略。
为什么是本地缓存而不是分布式群集缓存?
许多当前数据都是与业务无关的小数据缓存,不需要创建分布式群集缓存。 现在,订单和商品相关的数据,直接去数据库要求。 另外,除了构建分布式缓存外,群集维护成本高,不太适合紧急业务项目。
本节介绍使用缓存的三个阶段。 (摘自info架构师文档) ) ) )。
本地缓存在那个区域吗?
现在被认为占用了JVM的heap区域。 再细分一点的是heap中的old区域。 以现在的数据量来看,都是小数据,加起来不到几百兆。 放在heap区域是最快最方便的。 如果后期需要放在本地缓存中的数据很大,则可以考虑将其存储在off-heap区域(direct-memory或big-memory )中,但对于off-heap区域, 必须考虑对象的序列化((因为off-heap区域中存储的是二进制数据() ) ) ) ) )其实,如果数据量真的很大,实际上创建一个负责缓存的集中式缓存系统单体或集群都可以。
创建单实例模式,其中有Map变量放置数据
单示例模式是简单复杂的模式(3358 iam zhong Yong.iteye.com/blog/1539642 )。
典型的代码如下。
公共类单一贴图{
//本地缓存映射
privatemaplocalcachestore=new hashmap (;
//是私人对象,不是cbdqz模式
privatestaticsingletonmapsingletonmap=newsingletonmap (;
//私人结构方法,不能在外部新建一个对象
私密单次映射
}
//静态方法,从外部获取实例对象
publicstaticsingletonmapgetinstance (
返回单次映射;
}
//获取缓存中的数据
publicobjectgetvaluebykey (字符串密钥) {
returnlocalcachestore.get(key;
}
//将数据添加到缓存中
publicvoidputvalue (字符串密钥,对象值) {
localcachestore.put(key,value;
}
}
这个可以用吗? 可以使用,但非常有限
但是这样的是本地缓存吗? 答案明显不同,为什么呢?
1、没有缓存大小设置,不能限制“最大大小限制”和“存储数据限制”
2、缓存撤销策略(eviction policies );
3、在没有弱密钥引用、内存消耗紧张的情况下,不能回收JVM (weak rere rences keys );
4、无监测统计(统计;
5、持久性存储(永久存储);
所以,这种东西就这样废除了。
部署EhCache以构建缓存(3360http://ray chase.iteye.com/blog/1545906详细信息) ) ) )。
EhCahce核心类:
a、CacheManager:Cache的管理类;
b、Cache :负责缓存的get和put等操作的具体Cache类信息
c、缓存配置:缓存的配置信息。 包括策略、最大值等信息
d,element :缓存中单个缓存数据的单位
典型的代码如下。
publicstaticvoidmain (字符串[ ] args ) {
//EhCache缓存由缓存管理器管理
cachemanagercachemanager=cachemanager.getinstance (;
//缓存的配置也可以在xml文件中进行
cacheconfigurationconf=newcacheconfiguration (;
Conf.name(ca
che_name_default");//设置名字conf.maxEntriesLocalHeap(1000);//最大的缓存数量
conf.memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LRU);//设置失效策略
//创建一个缓存对象,并把设置的信息传入进去
Cache localCache = new Cache(conf);
//将缓存对象添加到管理器中
cacheManager.addCache(localCache);
localCache.put(new Element("iamzhongyong", new Date()));
System.out.println(localCache.getSize());
System.out.println(localCache.getStatistics().toString());
System.out.println(localCache.getName());
System.out.println(localCache.get("iamzhongyong").toString());
System.out.println(localCache.get("iamzhongyong").getObjectValue());
}
当然,Cache的配置信息,可以通过配置文件制定了。。。
优点:功能强大,有失效策略、最大数量设置等,缓存的持久化只有企业版才有,组件的缓存同步,可以通过jgroup来实现
缺点:功能强大的同时,也使其更加复杂
引入guava的cacheBuilder来构建缓存
这个非常强大、简单,通过一个CacheBuilder类就可以满足需求。
缺点就是如果要组件同步的话,需要自己实现这个功能。
典型的代码如下:
public class GuavaCacheBuilderTest {
public static void main(String[] args) throws Exception{
GuavaCacheBuilderTest cache = new GuavaCacheBuilderTest();
cache.getNameLoadingCache("bixiao");
}
public void getNameLoadingCache(String name) throws Exception{
LoadingCache cache = CacheBuilder.newBuilder()
.maximumSize(20)//设置大小,条目数
.expireAfterWrite(20, TimeUnit.SECONDS)//设置失效时间,创建时间
.expireAfterAccess(20, TimeUnit.HOURS) //设置时效时间,最后一次被访问
.removalListener(new RemovalListener() { //移除缓存的监听器
public void onRemoval(RemovalNotification notification) {
System.out.println("有缓存数据被移除了");
}})
.build(new CacheLoader(){ //通过回调加载缓存
@Override
public String load(String name) throws Exception {
return name + "-" + "iamzhongyong";
}
});
System.out.println(cache.get(name));
//cache.invalidateAll();
}
}
缓存预热怎么搞?
A、全量预热,固定的时间段移除所有,然后再全量预热
适用场景:
1、数据更新不频繁,例如每天晚上3点更新即可的需求;
2、数据基本没有变化,例如全国区域性数据;
B、增量预热(缓存查询,没有,则查询数据库,有则放入缓存)
适用场景:
1、 数据更新要求缓存中同步更新的场景
集群内部,缓存的一致性如何保证?
如果采用ehcache的话,可以使用框架本身的JGroup来实现组内机器之间的缓存同步。
如果是采用google的cacheBuilder的话,需要自己实现缓存的同步。
A、非实时生效数据:数据的更新不会时时发生,应用启动的时候更新即可,然后定时程序定时去清理缓存;
B、需要实时生效数据:启动时可预热也可不预热,但是缓存数据变更后,集群之间需要同步
原文:https://www.cnblogs.com/lyh971134228/p/6874432.html