hibernate的缓存机制
2015-11-08 15:05
190 查看
hibernate的缓存级别
首先,我们都知道,在使用hibernate的时候,数据都是将书卷转化为二进制流放在缓存中,然后再将缓存中的数据放入数据库的,这样一方面减少了数据库的压力,另一方面也提高了应用的效率。
首先提出问题:
缓存
1、缓存的生命周期
2、数据库的数据是怎么样放入到缓存中的
3、缓存中的数据是怎么样放入到数据库中的
4、客户端怎么样从缓存中把数据取出来
5、客户端怎么样把一个数据放入到缓存中
6、怎么样把一个对象从缓存中取出
7、把缓存中所有的数据清空
页面缓存:这个是一个题外话?也是遇到的问题?加入有一天客户端浏览网站,连续不断的在该网站上进行长达一段时间的数据交互,这个时候你就会发现网站就会变得非常非常的卡?只有关掉浏览器重来,或者刷新网页才可以继续使用。那原因在哪里呢?因为那些数据缓存都在内存上的,之所以卡,是因为缓存没清理,所以这个时候就提出了页面缓存,至于怎么用,请查阅资料。
案例:
session缓存:
1、生命周期就是session的生命周期
2、一级缓存存放的数据都是私有数据
把session存放在threadlocal中,不同的线程是不能访问的,所以保证了数据的安全性
3、怎么样把数据存放到一级缓存中
利用session.save/update/load/get方法都可以存放在一级缓存中
4、利用session.get/load方法可以把数据从一级缓存中取出
5、session.evict方法可以把一个对象从一级缓存中清空
6、利用session.clear方法可以把session中的所有的数据清空
7、利用session.Refresh方法把数据库中的数据同步到缓存中
8、session.flus:只是发出SQL语句了,并没有清空session缓存
在session的缓存内部,会去检查所有的持久化对象
1、如果一个持久化对象没有ID值,则会发出insert语句
2、如果一个持久化对象有ID值,则会去检查快照进行对比,如果一样,则什么都不做,如果不一样,则发出update语句
3、检查所有的持久化对象是否有关联对象
检查关联对象的级联操作
检查关联对象的关系操作
9、批量操作:大家想想批量操作,上面案例也写过。当缓存中的数据大到一定时候就会内存溢出,我们又改怎么解决呢?
批量插入数据到数据库的方法?(如;几千万条数据)
@Test
public void testSaveBatch(){
Session session = sessionfactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
for(int i=6;i<1000000;i++){
Classes classes = new Classes();
classes.setCname("aaa");
classes.setDescription("afds");
session.save(classes);
if(i%50==0){
session.flush();
session.clear();
}
}
transaction.commit();
}
缓存到数据库了,就不会发生溢出了。MySql数据库一百万条数据还行,单上千万就不行了。上亿就瘫痪了
内除溢出的状况:
所以解决办法有,就是在跟数据库提交数据库的时候,对内存的数据进行清除。
二、二级缓存和查询缓存
二级缓存:存放公有数据
1、适用场合:
1、数据不能频繁更新(电脑已启动,数据就加载到缓存中了,所以相对一级缓存来说,查询和提取数据就快多了)
2、数据能公开,私密性不是很强,不想一级缓存那样,每一个session对象都在ThreadLocal线程上的,各自独立,线程就是
安全的。
2、hibernate本身并没有提供二级缓存的解决方案
3、二级缓存的实现是依赖于第三方供应商完成的
ehcache
oscache
jbosscache
swamchache
4、二级缓存的操作
1、二级缓存存在sessionFactory中
2、生命周期:与sessionFactory保持一致
3、使用二级缓存的步骤(添加配置代码)
1、在hibernate.cfg.xml(这个是开启二级缓存)
<propertyname="cache.use_second_level_cache">true</property>
<propertyname="cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
2、让某一个对象进入到二级缓存中
* 在配置文件中(第一种方式,在配置文件中修改,不建议使用这种。)
<class-cacheusage="read-write"class="cn.itcast.hiberate.sh.domain.Classes"/>
* 在映射文件中(第二种方式,建议使用这种,分得清楚,在哪个映射文件中,使用的就是哪个对象)
<cacheusage="read-write"/>
3、使用
session.get/session.load
案例:
5、查询缓存:提出这个缓存的原因是:如果遇到查询大量的数据(如几百万条数据)放在内存中肯定不行,因为查询出来的数据都得先放在内存中,然后才开始进行取出,但是全部放在里面就会出现溢出错误!这是一个大错误。这个时候我们又该咋做?
第一种方式:
这种方式,保证查询条件都相同
等二种方法:利用ehcache.xml文件在磁盘存储缓存,文件配置指:用来指定缓存在磁盘上的存储位置。
ehcache.xml内容
文件解析:
name:缓存名称。
maxElementsInMemory:缓存最大个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属 性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当 eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一 个缓冲区。
maxElementsOnDisk:硬盘最大缓存个数。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略 是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。
更加详细的解析:点击打开链接
案例:
首先,我们都知道,在使用hibernate的时候,数据都是将书卷转化为二进制流放在缓存中,然后再将缓存中的数据放入数据库的,这样一方面减少了数据库的压力,另一方面也提高了应用的效率。
首先提出问题:
缓存
1、缓存的生命周期
2、数据库的数据是怎么样放入到缓存中的
3、缓存中的数据是怎么样放入到数据库中的
4、客户端怎么样从缓存中把数据取出来
5、客户端怎么样把一个数据放入到缓存中
6、怎么样把一个对象从缓存中取出
7、把缓存中所有的数据清空
页面缓存:这个是一个题外话?也是遇到的问题?加入有一天客户端浏览网站,连续不断的在该网站上进行长达一段时间的数据交互,这个时候你就会发现网站就会变得非常非常的卡?只有关掉浏览器重来,或者刷新网页才可以继续使用。那原因在哪里呢?因为那些数据缓存都在内存上的,之所以卡,是因为缓存没清理,所以这个时候就提出了页面缓存,至于怎么用,请查阅资料。
案例:
<span style="font-family:Microsoft YaHei;font-size:14px;"><span style="font-family:Microsoft YaHei;font-size:14px;">package cn.itcast.hibernate.test; import java.util.Set; import org.hibernate.Session; import org.hibernate.Transaction; import org.junit.Test; import cn.itcast.hibernate.domain.Classes; import cn.itcast.hibernate.domain.Student; import cn.itcast.hibernate.util.HibernateUtil; public class FirstCache extends HibernateUtil { static{ url="hibernate.cfg.xml"; } /** * session.get方法把数据存放在一级缓存中了 */ @Test public void sessionfac_crate(){ Session session=sessionfactory.getCurrentSession(); Transaction transaction=session.beginTransaction(); session.get(Classes.class, 1L); transaction.commit(); } /** * session.load方法把数据存放在一级缓存中 */ @Test public void testLoad(){ Session session = sessionfactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.load(Classes.class, 1L); classes.getCname(); classes = (Classes)session.load(Classes.class,1L); classes.getCname(); transaction.commit(); } /** * session.save方法把数据保存在一级缓存中 */ @Test public void testSave(){ Session session = sessionfactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = new Classes(); classes.setCname("aaa"); classes.setDescription("asfd"); session.save(classes); classes = (Classes)session.get(Classes.class, classes.getCid()); transaction.commit(); } /** * session.update讲述放入缓存中 */ @Test public void testUpdate(){ Session session = sessionfactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.get(Classes.class, 1L); session.evict(classes);//classes对象从session中清空了 session.update(classes);//把classes对象放入到了session缓存中 classes = (Classes)session.get(Classes.class, 1L); transaction.commit(); } /** * session.clear classes对象从session中清空了 */ @Test public void testClear(){ Session session = sessionfactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.get(Classes.class, 1L); session.clear();//classes对象从session中清空了 classes = (Classes)session.get(Classes.class, 1L); transaction.commit(); } @Test public void testClearTest(){ Session session = sessionfactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.get(Classes.class, 1L); session.clear();//如果不加这句话,两个不同的对象,相同的ID值,所以得把其中的一个清空 Classes classes2 = new Classes(); classes2.setCid(1L); classes2.setCname("asfd"); session.update(classes2); transaction.commit(); } /** * 把数据库中的数据刷新到缓存中 */ @Test public void testRefresh(){ Session session = sessionfactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.get(Classes.class, 1L); classes.setCname("66"); session.refresh(classes);//把cid为1的值从数据库刷到了缓存中(DB同步到缓存) System.out.println(classes.getCname()); transaction.commit(); } /** * session.flush//将缓存中的数据刷到数据库了。(缓存同步到DB) */ @Test public void testFlush(){ Session session = sessionfactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes =(Classes)session.get(Classes.class, 1L); classes.setCname("afdsasdf"); Set<Student> students = classes.getStudent(); for(Student student:students){ student.setDescription("asdf"); } session.flush(); transaction.commit(); } @Test public void testSaveBatch(){//这个例子是假设向数据库插入100万条数据,当然不能全部放在缓存中了,下面提出了解决办法 Session session = sessionfactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); for(int i=6;i<1000000;i++){ Classes classes = new Classes(); classes.setCname("aaa"); classes.setDescription("afds"); session.save(classes); if(i%50==0){ session.flush(); session.clear(); } } transaction.commit(); } /** * session.flush只是发出SQL语句了,并没有清空session缓存 */ @Test public void testFlush2(){ Session session = sessionfactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.get(Classes.class, 1L); session.flush(); classes = (Classes)session.get(Classes.class, 1L); transaction.commit(); } } </span></span>
session缓存:
1、生命周期就是session的生命周期
2、一级缓存存放的数据都是私有数据
把session存放在threadlocal中,不同的线程是不能访问的,所以保证了数据的安全性
3、怎么样把数据存放到一级缓存中
利用session.save/update/load/get方法都可以存放在一级缓存中
4、利用session.get/load方法可以把数据从一级缓存中取出
5、session.evict方法可以把一个对象从一级缓存中清空
6、利用session.clear方法可以把session中的所有的数据清空
7、利用session.Refresh方法把数据库中的数据同步到缓存中
8、session.flus:只是发出SQL语句了,并没有清空session缓存
在session的缓存内部,会去检查所有的持久化对象
1、如果一个持久化对象没有ID值,则会发出insert语句
2、如果一个持久化对象有ID值,则会去检查快照进行对比,如果一样,则什么都不做,如果不一样,则发出update语句
3、检查所有的持久化对象是否有关联对象
检查关联对象的级联操作
检查关联对象的关系操作
9、批量操作:大家想想批量操作,上面案例也写过。当缓存中的数据大到一定时候就会内存溢出,我们又改怎么解决呢?
批量插入数据到数据库的方法?(如;几千万条数据)
@Test
public void testSaveBatch(){
Session session = sessionfactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
for(int i=6;i<1000000;i++){
Classes classes = new Classes();
classes.setCname("aaa");
classes.setDescription("afds");
session.save(classes);
if(i%50==0){
session.flush();
session.clear();
}
}
transaction.commit();
}
缓存到数据库了,就不会发生溢出了。MySql数据库一百万条数据还行,单上千万就不行了。上亿就瘫痪了
内除溢出的状况:
所以解决办法有,就是在跟数据库提交数据库的时候,对内存的数据进行清除。
二、二级缓存和查询缓存
二级缓存:存放公有数据
1、适用场合:
1、数据不能频繁更新(电脑已启动,数据就加载到缓存中了,所以相对一级缓存来说,查询和提取数据就快多了)
2、数据能公开,私密性不是很强,不想一级缓存那样,每一个session对象都在ThreadLocal线程上的,各自独立,线程就是
安全的。
2、hibernate本身并没有提供二级缓存的解决方案
3、二级缓存的实现是依赖于第三方供应商完成的
ehcache
oscache
jbosscache
swamchache
4、二级缓存的操作
1、二级缓存存在sessionFactory中
2、生命周期:与sessionFactory保持一致
3、使用二级缓存的步骤(添加配置代码)
1、在hibernate.cfg.xml(这个是开启二级缓存)
<propertyname="cache.use_second_level_cache">true</property>
<propertyname="cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
2、让某一个对象进入到二级缓存中
* 在配置文件中(第一种方式,在配置文件中修改,不建议使用这种。)
<class-cacheusage="read-write"class="cn.itcast.hiberate.sh.domain.Classes"/>
* 在映射文件中(第二种方式,建议使用这种,分得清楚,在哪个映射文件中,使用的就是哪个对象)
<cacheusage="read-write"/>
3、使用
session.get/session.load
案例:
<span style="font-family:Microsoft YaHei;font-size:14px;"><span style="font-family:Microsoft YaHei;font-size:14px;">package cn.itcast.hibernate.test; import java.util.List; import org.hibernate.Query; import org.hibernate.Session; import org.junit.Test; import cn.itcast.hibernate.domain.Classes; import cn.itcast.hibernate.util.HibernateUtil; public class SecondLevalCache extends HibernateUtil { static{ url="hibernate.cfg.xml"; } /** * session.get * 把数据存在一级缓存和二级缓存(当然前提是这个持久化类是开启二级缓存的,不然就是在一级缓存) */ @Test public void testGet(){ Session session = sessionfactory.openSession(); Classes classes = (Classes)session.get(Classes.class, 1L); session.close();//一级缓存就没了 session = sessionfactory.openSession(); classes = (Classes)session.get(Classes.class, 1L); session.close(); //找数据--找一级缓存---找二级缓存---找数据库----最后才报错 } /** * session.load * 同上 */ @Test public void testLoad(){ Session session = sessionfactory.openSession(); Classes classes = (Classes)session.load(Classes.class, 1L); classes.getCname(); session.close(); session = sessionfactory.openSession(); classes = (Classes)session.load(Classes.class, 1L); classes.getCname(); session.close(); } /** * session.update */ @Test public void testUpdate(){ Session session = sessionfactory.openSession(); //session.beginTransaction(); Classes classes = new Classes(); classes.setCid(1L); classes.setCname("aaa"); session.update(classes); session.close(); session = sessionfactory.openSession(); classes = (Classes)session.get(Classes.class, 1L);//如果有sql语句说明就加载到一级缓存中了 session.close(); } } </span></span>
5、查询缓存:提出这个缓存的原因是:如果遇到查询大量的数据(如几百万条数据)放在内存中肯定不行,因为查询出来的数据都得先放在内存中,然后才开始进行取出,但是全部放在里面就会出现溢出错误!这是一个大错误。这个时候我们又该咋做?
第一种方式:
<span style="font-family:Microsoft YaHei;font-size:14px;"><span style="font-family:Microsoft YaHei;font-size:14px;">/** * 查询缓存:必须建立在二级缓存之上,当查询数据大的时候就需要查询缓存来优化了 * 首先在配置文件中配置:<!-- cache.use_query_cache:查询缓存的设置 --> * <property name="cache.use_query_cache">true</property> */ @Test public void testQuery(){ Session session = sessionfactory.openSession(); Query query = session.createQuery("from Classes"); query.setCacheable(true);//classes里的所有的数据要往查询缓存中存放了 List<Classes> classesList = query.list(); query = session.createQuery("from Classes"); query.setCacheable(true); classesList = query.list(); session.close(); }</span></span>
这种方式,保证查询条件都相同
等二种方法:利用ehcache.xml文件在磁盘存储缓存,文件配置指:用来指定缓存在磁盘上的存储位置。
ehcache.xml内容
<span style="font-family:Microsoft YaHei;font-size:14px;"><span style="font-family:Microsoft YaHei;font-size:14px;"><ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> <diskStore path="C:\\TEMP1"/> <defaultCache maxElementsInMemory="5" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="false" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> <Cache name="cn.itcast.hibernate.domain.Classes" maxElementsInMemory="3" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> </ehcache> </span></span>
文件解析:
name:缓存名称。
maxElementsInMemory:缓存最大个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属 性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当 eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一 个缓冲区。
maxElementsOnDisk:硬盘最大缓存个数。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略 是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。
更加详细的解析:点击打开链接
案例:
<span style="font-family:Microsoft YaHei;font-size:14px;"><span style="font-family:Microsoft YaHei;font-size:14px;"> /** * 查询缓存利用ehcache.xml文件来在当地磁盘上写缓存。 */ @Test public void testAllClasses(){ Session session = sessionfactory.openSession(); List<Classes> classesList = session.createQuery("from Classes").list(); session.close(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } }</span></span>
相关文章推荐
- Affinity Mask and Process Affinity
- 《最好的告别》
- socket 收发聊天内容
- linux命令-vim编辑模式
- 信息安全系统设计基础第九周学习总结
- 进位制换算
- Log4j没有正确配置导致项目没有发布成功
- Ubuntu 14.04安装Hadoop2.5.2(单机模式)
- eclipse安装maven
- Win7或Win8上安装VS2015报“安装包丢失或损坏”问题的解决办法
- LeetCode17:Letter Combinations of a Phone Number
- 分享WCF文件传输实现方法---WCFFileTransfer
- WebService
- 容器Collection_Set_List_ArrayListJAVA099-102
- 信息安全系统设计基础第九周学习总结
- 维度模型数据仓库(九) —— 角色扮演维度
- 【Oracle】--"任性"Oracle安装之旅
- 数据结构实践项目——图的基本运算及遍历操作
- [置顶] 在指定的 DSN 中,ODBC驱动程序和应用程序之间的体系结构不匹配解决方法
- Ubuntu's Trash