Hibernate之二 一級快取(session)、二級快取(sessionFactory)
一、操作Session快取
(1)flush
Session 按照快取中物件的屬性變化來同步更新資料庫
1)預設情況下 Session 在以下時間點重新整理快取:
顯式呼叫 Session 的 flush() 方法
當應用程式呼叫 Transaction 的 commit()方法的時, 該方法先 flush ,然後在向資料庫提交事務
當應用程式執行一些查詢(HQL, Criteria)操作時,如果快取中持久化物件的屬性已經發生了變化,會先 flush 快取,以保證查詢結果能夠反映持久化物件的最新狀態
(2)refresh2)flush 快取的例外情況: 如果物件使用 native 生成器生成 OID, 那麼當呼叫 Session 的 save() 方法儲存物件時, 會立即執行向資料庫插入該實體的 insert 語句.
3)commit() 和 flush() 方法的區別:flush 執行一系列 sql 語句,但不提交事務;commit 方法先呼叫flush() 方法,然後提交事務. 意味著提交事務意味著對資料庫操作永久儲存下來。
4)若希望改變 flush 的預設時間點, 可以通過 Session 的 setFlushMode() 方法顯式設定 flush 的時間點
(3)clear會強制傳送 SELECT 語句, 以使 Session 快取中物件的狀態和資料表中對應的記錄保持一致!
進行一次查詢後,由於session快取,第二次查詢時,將不再發送SQl語句,但是如果呼叫的refresh方法,則強制傳送sql語句進行查詢。
<span style="font-size:14px;"> News news = (News) session.get(News.class, 1); System.out.println(news); session.refresh(news); System.out.println(news); </span>
清理快取
<span style="font-size:14px;"> News news1 = (News) session.get(News.class, 1); session.clear(); News news2 = (News) session.get(News.class, 1);</span>
二、持久化物件的狀態
臨時物件(Transient):
在使用代理主鍵的情況下, OID 通常為 null
不處於 Session 的快取中
在資料庫中沒有對應的記錄
持久化物件(也叫”託管”)(Persist):
OID 不為 null
位於 Session 快取中
若在資料庫中已經有和其對應的記錄, 持久化物件和資料庫中的相關記錄對應
Session 在 flush 快取時, 會根據持久化物件的屬性變化, 來同步更新資料庫
在同一個 Session 例項的快取中, 資料庫表中的每條記錄只對應唯一的持久化物件
刪除物件(Removed)
在資料庫中沒有和其 OID 對應的記錄
不再處於 Session 快取中
一般情況下, 應用程式不該再使用被刪除的物件
遊離物件(也叫”脫管”) (Detached):
OID 不為 null
不再處於 Session 快取中
一般情況需下, 遊離物件是由持久化物件轉變過來的, 因此在資料庫中可能還存在與它對應的記錄
(1)save()
Session 的 save() 方法使一個臨時物件轉變為持久化物件
Session 的 save() 方法完成以下操作:
把 News 物件加入到 Session 快取中, 使它進入持久化狀態
選用對映檔案指定的識別符號生成器, 為持久化物件分配唯一的 OID. 在 使用代理主鍵的情況下, setId() 方法為 News 物件設定 OID 使無效的.
計劃執行一條 insert 語句:在 flush 快取的時候
Hibernate 通過持久化物件的 OID 來維持它和資料庫相關記錄的對應關係. 當 News 物件處於持久化狀態時, 不允許程式隨意修改它的 ID
persist() 和 save() 區別:
當對一個 OID 不為 Null 的物件執行 save() 方法時, 會把該物件以一個新的 oid 儲存到資料庫中; 但執行 persist() 方法時會丟擲一個異常.
(2)get() 和 load()
都可以根據跟定的 OID 從資料庫中載入一個持久化物件
當資料庫中不存在與 OID 對應的記錄時
load() 方法丟擲 ObjectNotFoundException 異常
get() 方法返回 null
兩者採用不同的延遲檢索策略:load 方法支援延遲載入策略。而 get 不支援。
(3)update()
Session 的 update() 方法使一個遊離物件轉變為持久化物件, 並且計劃執行一條 update 語句.
若希望 Session 僅當修改了 News 物件的屬性時, 才執行 update() 語句, 可以把對映檔案中 <class> 元素的 select-before-update 設為 true. 該屬性的預設值為 false
當 update() 方法關聯一個遊離物件時, 如果在 Session 的快取中已經存在相同 OID 的持久化物件, 會丟擲異常
當 update() 方法關聯一個遊離物件時, 如果在資料庫中不存在相應的記錄, 也會丟擲異常.
(4)saveOrUpdate()
首先判斷儲存的物件是臨時物件還是遊離物件,若為臨時物件,則呼叫save()方法,若是遊離物件,則呼叫update()方法。
判定物件為臨時物件的標準
- Java 物件的 OID 為 null
- 對映檔案中為 <id> 設定了 unsaved-value 屬性, 並且 Java 物件的 OID 取值與這個 unsaved-value 屬性值匹配
(5)delete()
Session 的 delete() 方法既可以刪除一個遊離物件, 也可以刪除一個持久化物件
Session 的 delete() 方法處理過程
計劃執行一條 delete 語句
把物件從 Session 快取中刪除, 該物件進入刪除狀態.
Hibernate 的 cfg.xml 配置檔案中有一個 hibernate.use_identifier_rollback 屬性, 其預設值為 false, 若把它設為 true, 將改變 delete() 方法的執行行為: delete() 方法會把持久化物件或遊離物件的 OID 設定為 null, 使它們變為臨時物件
二、二級快取
1. 加入二級快取外掛EHCache的 jar 包及配置檔案:
I. EHCache依賴的jar包
ehcache-core-2.4.3.jar
hibernate-ehcache-4.2.4.Final.jar
slf4j-api-1.6.1.jar
II. EHCache的配置檔案複製到src下 ehcache.xml
<ehcache>
<!-- Sets the path to the directory where cache .data files are created.
If the path is a Java System Property it is replaced by
its value in the running VM.
The following properties are translated:
user.home - User's home directory
user.dir - User's current working directory
java.io.tmpdir - Default temp file path -->
<!--
指定一個目錄:當 EHCache 把資料寫到硬碟上時, 將把資料寫到這個目錄下.
-->
<diskStore path="d:\\tempDirectory"/>
<!--Default Cache configuration. These will applied to caches programmatically created through
the CacheManager.
The following attributes are required for defaultCache:
maxInMemory - Sets the maximum number of objects that will be created in memory
eternal - Sets whether elements are eternal. If eternal, timeouts are ignored and the element
is never expired.
timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used
if the element is not eternal. Idle time is now - last accessed time
timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used
if the element is not eternal. TTL is now - creation time
overflowToDisk - Sets whether elements can overflow to disk when the in-memory cache
has reached the maxInMemory limit.
-->
<!--
設定快取的預設資料過期策略
-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
<!--
設定具體的命名快取的資料過期策略。每個命名快取代表一個快取區域
快取區域(region):一個具有名稱的快取塊,可以給每一個快取塊設定不同的快取策略。
如果沒有設定任何的快取區域,則所有被快取的物件,都將使用預設的快取策略。即:<defaultCache.../>
Hibernate 在不同的快取區域儲存不同的類/集合。
對於類而言,區域的名稱是類名。如:com.atguigu.domain.Customer
對於集合而言,區域的名稱是類名加屬性名。如com.atguigu.domain.Customer.orders
-->
<!--
name: 設定快取的名字,它的取值為類的全限定名或類的集合的名字
maxElementsInMemory: 設定基於記憶體的快取中可存放的物件最大數目
eternal: 設定物件是否為永久的, true表示永不過期,
此時將忽略timeToIdleSeconds 和 timeToLiveSeconds屬性; 預設值是false
timeToIdleSeconds:設定物件空閒最長時間,以秒為單位, 超過這個時間,物件過期。
當物件過期時,EHCache會把它從快取中清除。如果此值為0,表示物件可以無限期地處於空閒狀態。
timeToLiveSeconds:設定物件生存最長時間,超過這個時間,物件過期。
如果此值為0,表示物件可以無限期地存在於快取中. 該屬性值必須大於或等於 timeToIdleSeconds 屬性值
overflowToDisk:設定基於記憶體的快取中的物件數目達到上限後,是否把溢位的物件寫到基於硬碟的快取中
-->
<cache name="com.atguigu.hibernate.entities.Employee"
maxElementsInMemory="1"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
<cache name="com.atguigu.hibernate.entities.Department.emps"
maxElementsInMemory="1000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
/>
</ehcache>
2.在hibernate.cfg.xml檔案中進行配置
I. 配置啟用 hibernate 的二級快取
<property name="cache.use_second_level_cache">true</property>
II. 配置hibernate二級快取使用的產品
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
III. 配置對哪些類使用 hibernate 的二級快取
<class-cache usage="read-write" class="com.atguigu.hibernate.entities.Employee"/>
3. 集合級別的二級快取的配置
I. 配置對集合使用二級快取 hibernate.hbm.xml
<collection-cache usage="read-write" collection="com.atguigu.hibernate.entities.Department.emps"/>
也可以在 .hbm.xml 檔案中進行配置
<set name="emps" table="GG_EMPLOYEE" inverse="true" lazy="true">
<cache usage="read-write"/>
<key>
<column name="DEPT_ID" />
</key>
<one-to-many class="com.atguigu.hibernate.entities.Employee" />
</set>
II. 注意: 還需要配置集合中的元素對應的持久化類也使用二級快取! 否則將會多出 n 條 SQL 語句.
<class-cache usage="read-write" class="com.atguigu.hibernate.entities.Employee"/>