20.session的一級緩存
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();
}
}
21.二級緩存
二級緩存:存放公有資料
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();
}
<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();
}
}