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(); }
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(); } }