标题1 缓存的模拟
public class CacheDemo {
//缓存容器
private static Map adminCache =new HashMap();
static AdminInfo getAdminById(int id) {
//先去缓存中看有没有数据
String key=AdminInfo.class.getName()+id;
AdminInfo admin=(AdminInfo)adminCache.get(key);
//如果缓存中没有数据,则去数据库中查询
if(admin==null) {
admin= HibUtil.get(AdminInfo.class, id);
adminCache.put(key,admin);
System.out.println("从数据库中查询..");
}
else {
System.out.println("从缓存中取的..");
}
return admin;
}
public static void update(AdminInfo admin) {
HibUtil.update(admin);
String key=admin.getClass().getName()+admin.getId();
//adminCache.put(key,admin);
adminCache.remove(key);
}
public static void delete(AdminInfo admin) {
HibUtil.delete(admin);
String key=admin.getClass().getName()+admin.getId();
adminCache.remove(key);
}
public static void main(String[] args) {
System.out.println( getAdminById(1));
System.out.println( getAdminById(1));
AdminInfo admin=new AdminInfo();
admin.setId(1);
admin.setAdminName("赵强");
update(admin);
System.out.println( getAdminById(1));
System.out.println( getAdminById(1));
delete(admin);
System.out.println( getAdminById(1));
System.out.println( getAdminById(1));
}
}
主要有几点
1) 缓存容器是全局的,对所有的线程都可见,共享
2) 缓存的key 用的是 类名+ id
3) 要注意在对象进行更新或删除的时候,进行缓存同步
标题2 hibernate 的一级缓存
hibernate 中的缓存有两种, 一级缓存,二级缓存
一级缓存:Session范围内的
二及缓存:SessionFactory 范围内的
//例子: 一级缓存
void test() {
Session s=HibUtil.getSession();
AdminInfo a1 =s.get(AdminInfo.class, 1);
AdminInfo a2 =s.get(AdminInfo.class, 1);
AdminInfo a3 =s.get(AdminInfo.class,2);
AdminInfo a4 =s.get(AdminInfo.class, 1);
AdminInfo a5 =s.get(AdminInfo.class, 2);
HibUtil.closeSession();
}
可以发现,最终就输出2条语句, 因为缓存了2个对象,其他的查询都是从缓存中取的
关于上面的一级缓存的说明
1)它的key 就是 AdminInfo.class +id
2)一级缓存的有效空间就是在Session范围内,生命周期特别短,不实用
3)save, update,saveOrUpdate,load,get,list,lock,iterator 等方法都会把对象添到一级缓存中
4)Session evict ,clear 等方法可以清除一级缓存
s.evice(admin) //只清除一个
s.clear() //清除所有
5) 一级缓存不能控制缓存对象的个数,如果有大量的对象要缓存,可能会造成内存溢出,注意处理
void test() {
Session s=HibUtil.getSession();
for(int i=0;i<999999999;i++) {
if(i%200==0) {
s.flush(); //同步一级缓存中的内容到数据库中
s.clear(); //清除一缓存
}
AdminInfo admin=new AdminInfo();
admin.setAdminName("用户_"+i);
s.save(admin);
}
HibUtil.closeSession();
}
标题 3 hbiernate 的二级缓存
SessionFactory范围的
hibernate把缓存的管理交给了缓存框架去实现 (要有对应的jar包)
1) 导包
/lib/optional/ehcache
ehcache-2.10.6.jar
hibernate-ehcache-5.4.14.Final.jar
slf4j-api-1.7.25.jar
2) 在配置文件中声明启用二级缓存
hibernate.cache.use_second_level_cache true //默认是注起来的,而且后面是false,把它改成true
3) 生成统计信息( 在开发的时候用,是可选的 )
hibernate.generate_statistics true //默认是注起来的
-
选择缓存提供者
#hibernate.cache.region.factory_class org.hibernate.cache.infinispan.InfinispanRegionFactory
#hibernate.cache.region.factory_class org.hibernate.cache.infinispan.JndiInfinispanRegionFactory
hibernate.cache.region.factory_class org.hibernate.cache.internal.EhCacheRegionFactory //这个地方配置文件和官方文档错了
org.hibernate.cache.ehcache.internal.EhcacheRegionFactory 要写成这个样子#hibernate.cache.region.factory_class org.hibernate.cache.internal.SingletonEhCacheRegionFactory #hibernate.cache.region.factory_class org.hibernate.cache.internal.NoCachingRegionFactory
-
指明哪个类要用二级缓存
在主配置文件 hibernate.cfg.xml 中
要写在下面 或者写在映射文件中 <class name="AdminInfo" > <cache usage="read-write"/> //写在这个位置 <id name="id"> <generator class="native" /> </id> <property name="password" /> <property name="note" /> <property name="adminName" /> </class> public static void main(String[] args) { HibUtil.get(AdminInfo.class,1); HibUtil.get(AdminInfo.class,1); HibUtil.get(AdminInfo.class,2); HibUtil.get(AdminInfo.class,1); HibUtil.get(AdminInfo.class,1); HibUtil.get(AdminInfo.class,1); //得到缓存相关的统计信息 Statistics total= HibUtil.getSessionFactory().getStatistics(); System.out.println(total); System.out.println("二级缓存存入 "+ total.getSecondLevelCachePutCount() +"次"); //2 System.out.println("二级缓命中 "+ total.getSecondLevelCacheHitCount() +"次"); //4 System.out.println("二级缓存错过 "+ total.getSecondLevelCacheMissCount() +"次"); //2 }
通常来说,我们还要配置它的级配置文件
ehcache.xml 可以从 project/etc 目录下找到
里面的主要配置
<diskStore path="java.io.tmpdir"/> //用来指定缓存的存放位置 <diskStore path="c:/cache/xxxx"/>
<defaultCache
maxElementsInMemory=“10000” //内存中最多可以存多少对象
eternal=“false” //指定缓存是不是永不过期
timeToIdleSeconds=“120” //缓存的空闲时间(秒),过期以后会被删除
timeToLiveSeconds=“120” //缓存对象一共要存在多久
overflowToDisk=“true” //超过个数 (maxElementsInMemory 指定的个数)以后,是不是要往磁盘上存
diskPersistent=“true” //指的是jvm结束后,是不是要把缓存存到磁盘上
diskExpiryThreadIntervalSeconds=“60” //清除缓存的线程的轮循时间
/>
我们可以尝试让它把缓存存到磁盘上
<diskStore path="c:/cache/xxxx"/> 内存中的对象超出以后,放在这个位置
<defaultCache
maxElementsInMemory="1" //让内容中只能装下一个对象
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
关于二级缓存
1)哪些方法可以填充二级缓存
get ,save ( 不适合native主键的 ) , update,saveOrUpdate,load,list,iterator,Query ,Criteria 都会填充二级缓存
在查询的时候,昼量不要用 iterator 去处理数据,它可能存在N+1 次查询的问题
Query ,Criteria 缓存命中率比较低,而且可能要缓存的数量据也特别大, 在hibernate中默认是关闭的
可以用 在配置文件中配置 hibernate.cache.use_query_cache true
( 它会把查询条件做为key,查出来的结果做为value )
- 清除二级缓存
//这是版本3
HibUitl.getSessionFactory().evict(AdminInfo.class); //清除AdminInfo 对象的所有缓存
HibUitl.getSessionFactory().evict(AdminInfo.class,1); //清除id为1的AdminInfo对象的缓存
//这是版本5
HibUtil.getSessionFactory().getCache().evictAll(); //清除所有
HibUtil.getSessionFactory().getCache().evict(AdminInfo.class);
- 下面的操作,会导致所有的二级缓存被清除
Query q=s.createQuery("update admin set adminName= ‘xxx’ ");
q.executeUpdate();