1.什么是缓存?
缓存是介于物理数据源与应用程序之间,是对数据库中的数据复制一份临时放在内存中的容器,其作用是为了减少应用程序对物理数据源访问的次数,从而提高了应用程序的运行性能。Hibernate在进行读取数据的时候,根据缓存机制在相应的缓存中查询,如果在缓存中找到了需要的数据(我们把这称做“缓存命 中"),则就直接把命中的数据作为结果加以利用,避免了大量发送SQL语句到数据库查询的性能损耗。
2.Hibernate缓存分类:
一、Session缓存(又称作事务缓存):Hibernate内置的,不能卸除。
缓存范围:缓存只能被当前Session对象访问。缓存的生命周期依赖于Session的生命周期,当Session被关闭后,缓存也就结束生命周期。
二、SessionFactory缓存(又称作应用缓存):使用第三方插件,可插拔。
缓存范围:缓存被应用范围内的所有session共享,不同的Session可以共享。这些session有可能是并发访问缓存,因此必须对缓存进行更新。缓存的生命周期依赖于应用的生命周期,应用结束时,缓存也就结束了生命周期,二级缓存存在于应用程序范围。
缓存策略提供商:
提供了HashTable缓存,EHCache,OSCache,SwarmCache,jBoss Cathe2,这些缓存机制,其中EHCache,OSCache是不能用于集群环境(Cluster Safe)的,而SwarmCache,jBoss Cathe2是可以的。HashTable缓存主要是用来测试的,只能把对象放在内存中,EHCache,OSCache可以把对象放在内存(memory)中,也可以把对象放在硬盘(disk)上(为什么放到硬盘上?上面解释了)。
session的缓存:
1、生命周期就是session的生命周期
2、session一级缓存存放的数据都是私有数据
把session存放在threadlocal中,不同的线程是不能访问的,所以保证了数据的安全性
3、怎么样把数据存放到一级缓存中
利用session.save/update/load/get方法都可以存放在一级缓存中
4、利用session.get/load方法可以把数据从一级缓存中取出
5、session.evict方法可以把一个对象从一级缓存中清空
6、利用session.clear方法可以把session中的所有的数据清空
7、利用session.Refresh方法把数据库中的数据同步到缓存中
8、session.flush
在session的缓存内部,会去检查所有的持久化对象
1、如果一个持久化对象没有ID值,则会发出insert语句
2、如果一个持久化对象有ID值,则会去检查快照进行对比,如果一样,则什么都不做,如果不一样,则发出update语句
3、检查所有的持久化对象是否有关联对象
检查关联对象的级联操作
检查关联对象的关系操作
9、批量操作
测试
public class SessionCacheTest extends HibernateUtils{
@Test
public void testGet(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Classess Classess = (Classess)session.get(Classess.class, 1L);
Classess = (Classess)session.get(Classess.class,1L);
transaction.commit();
}
/**
* session.load方法把数据存放在一级缓存中
*/
@Test
public void testLoad(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Classess Classess = (Classess)session.load(Classess.class, 1L);
Classess.getCname();
Classess = (Classess)session.load(Classess.class,1L);
Classess.getCname();
transaction.commit();
}
/**
* session.save方法把数据保存在一级缓存中
*/
@Test
public void testSave(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Classess Classess = new Classess();
Classess.setCname("aaa");
Classess.setDescription("asfd");
session.save(Classess);
Classess = (Classess)session.get(Classess.class, Classess.getCid());
transaction.commit();
}
/**
* session.update
*/
@Test
public void testUpdate(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Classess Classess = (Classess)session.get(Classess.class, 1L);
session.evict(Classess);//Classess对象从session中清空了
session.update(Classess);//把Classess对象放入到了session缓存中
Classess = (Classess)session.get(Classess.class, 1L);
transaction.commit();
}
/**
* session.clear
*/
@Test
public void testClear(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Classess Classess = (Classess)session.get(Classess.class, 1L);
session.clear();//Classess对象从session中清空了
Classess = (Classess)session.get(Classess.class, 1L);
transaction.commit();
}
@Test
public void testClearTest(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Classess Classess = (Classess)session.get(Classess.class, 1L);
session.clear();//如果不加这句话,两个不同的对象,相同的ID值,所以得把其中的一个清空
Classess Classess2 = new Classess();
Classess2.setCid(1L);
Classess2.setCname("asfd");
session.update(Classess2);
transaction.commit();
}
/**
* 把数据库中的数据刷新到缓存中
*/
@Test
public void testRefresh(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Classess Classess = (Classess)session.get(Classess.class, 1L);
Classess.setCname("66");
session.refresh(Classess);//把cid为1的值从数据库刷到了缓存中
System.out.println(Classess.getCname());
transaction.commit();
}
/**
* session.flush
*/
@Test
public void testFlush(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Classess Classess =(Classess)session.get(Classess.class, 1L);
Classess.setCname("afdsasdf");
Set<Student> students = Classess.getStudents();
for(Student student:students){
student.setDescription("asdf");
}
session.flush();
transaction.commit();
}
/**
* 批量操作
*/
@Test
public void testSaveBatch(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
for(int i=6;i<1000000;i++){
Classess Classess = new Classess();
Classess.setCname("aaa");
Classess.setDescription("afds");
session.save(Classess);
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();
Classess Classess = (Classess)session.get(Classess.class, 1L);
session.flush();
Classess = (Classess)session.get(Classess.class, 1L);
transaction.commit();
}
}二级缓存:存放公有数据
1、适用场合:
1、数据不能频繁更新
2、数据能公开,私密性不是很强
2、hibernate本身并没有提供二级缓存的解决方案
(1.在hibernate中二级缓存用的不多,如果数据跟新频繁,是不会放入二级缓存之中不会提高效率,2.如果不用跟新,直接和数据库交互3.因为是公有数据,每个线程访问还有加密?不懂 )
3、二级缓存的实现是依赖于第三方供应商完成的
ehcache
oscache
jbosscache
swamchache
4、二级缓存的操作
1、二级缓存存在sessionFactory中
2、生命周期:与sessionFactory保持一致(容器启动sessionFactory产生,容器关闭sessionFactory关闭)
3、使用二级缓存的步骤
1、在hibernate.cfg.xml
<property name="cache.use_second_level_cache">true</property>
<property name="cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
2、让某一个对象进入到二级缓存中
* 在配置文件中
<class-cache usage="read-only" class="cn.itcast.hiberate.sh.domain.Classes"/>
* 在映射文件中
<cache usage="read-only"/>
3、使用
session.get/session.load
/**
* session.get
* 把数据存在一级缓存和二级缓存
*/
@Test
public void testGet11(){
Session session = sessionFactory.openSession();
Classess Classess = (Classess)session.get(Classess.class, 1L);
session.close();
session = sessionFactory.openSession();
Classess = (Classess)session.get(Classess.class, 1L);
session.close();
}
/**
* session.load
* 同上
*/
@Test
public void testLoad22(){
Session session = sessionFactory.openSession();
Classess Classess = (Classess)session.load(Classess.class, 1L);
Classess.getCname();
session.close();
session = sessionFactory.openSession();
Classess = (Classess)session.load(Classess.class, 1L);
Classess.getCname();
session.close();
}
/**
* session.update
*/
@Test
public void testUpdate11(){
Session session = sessionFactory.openSession();
//session.beginTransaction();
Classess Classess = new Classess();
Classess.setCid(1L);
Classess.setCname("aaa");
session.update(Classess);
session.close();
session = sessionFactory.openSession();
Classess = (Classess)session.get(Classess.class, 1L);
session.close();
}5、查询缓存
在hibernate配置文件添加<property name="cache.use_query_cache">true</property>
@Test
public void testQuery(){
Session session = sessionFactory.openSession();
Query query = session.createQuery("from Classess");
query.setCacheable(true);//Classess里的所有的数据要往查询缓存中存放了
List<Classess> ClassessList = query.list();
query = session.createQuery("from Classess");//查询缓存中的数据,sql语句必须和缓存的数据一致,才能利用查询缓存
query.setCacheable(true);//取出缓存数据
ClassessList = query.list();
session.close();
}
6.大量数据缓存
在src下添加一个配置文件ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore path="D:\\TEMP1"/>
<defaultCache
maxElementsInMemory="12"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
<Cache
name="cn.itcast.domain.Classes"
maxElementsInMemory="5"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
</ehcache>
@Test
public void testAllClassess(){
Session session = sessionFactory.openSession();
List<Classess> ClassessList = session.createQuery("from Classess").list();
session.close();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}原文:http://pengya123.blog.51cto.com/8467424/1811634