Hibernate中對象的狀態:java
學習Hibernate的對象狀態是爲了更清晰地知道Hibernate的設計思想,以及是一級緩存的基礎...固然啦,也就一點點知識sql
當咱們直接new出來的對象就是臨時/瞬時狀態的..數據庫
當保存在數據庫中的對象就是持久化狀態了緩存
咱們來測試一下:當對對象屬性進行更改的時候,會反映到數據庫中!微信
session.save(idCard);
idCard.setIdCardName("我是測試持久化對象");
複製代碼
當Session關閉了之後,持久化的對象就變成了遊離狀態了...session
Hibernate有一級緩存和二級緩存之分,這裏主要講解一級緩存框架
Hibenate中一級緩存,也叫作session的緩存,它能夠在session範圍內減小數據庫的訪問次數! 只在session範圍有效! Session關閉,一級緩存失效!ide
只要是持久化對象狀態的,都受Session管理,也就是說,都會在Session緩存中!性能
Session的緩存由hibernate維護,用戶不能操做緩存內容; 若是想操做緩存內容,必須經過hibernate提供的evit/clear方法操做。學習
減小對數據庫的訪問次數!從而提高hibernate的執行效率!
咱們來看一下Hibernate是怎麼減小對數據庫訪問的次數的。
如今個人User表有這麼一條記錄:
//把數據放進cache
User user = (User) session.get(User.class, 1);
//發現要修改的字段和cache同樣,不執行
user.setUserName("你好2");
複製代碼
取數據也是同樣的
User user = null;
user = (User) session.get(User.class, 1);
user = (User) session.get(User.class, 1);
複製代碼
和緩存有關經常使用的方法有三個:
session.flush(); 讓一級緩存與數據庫同步
session.evict(arg0); 清空一級緩存中指定的對象
session.clear(); 清空一級緩存中緩存的全部對象
clear
User user = null;
user = (User) session.get(User.class, 1);
//清除緩存,那麼下面獲取的時候,就不能從緩存裏面拿了
session.clear();
user = (User) session.get(User.class, 1);
複製代碼
在有緩存的狀況下,修改同一條記錄的數據,以最後的爲準...所以只有一條update
User user = null;
user = (User) session.get(User.class, 1);
user.setUserName("我是第一");
user = (User) session.get(User.class, 1);
user.setUserName("我是第二");
複製代碼
我讓強制讓它和數據庫同步的話,就有兩條update了
User user = null;
user = (User) session.get(User.class, 1);
user.setUserName("我是第一");
session.flush();
user = (User) session.get(User.class, 1);
user.setUserName("我是第二");
複製代碼
通常地,咱們在批處理的時候會用,由於緩存也是有大小的,若是1000條數據插入進去都要緩存,那麼Hibernate可能就崩了...
值得注意的是:不一樣的Session是不會共享緩存的!
咱們使用HQL查詢所有數據的時候,可使用list()獲得全部的數據,也可使用iterator()獲得一個迭代器,再遍歷迭代器...那它們有什麼區別呢?
。。。。當時看視頻的時候說是下圖:
可是我在測試的時候:List也能夠獲取緩存的數據
固然啦,Iterator也是能夠獲取緩存的數據
所以,在獲取數據的時候仍是使用list()方便!
懶加載就是當使用數據的時候纔去獲取數據、執行對應的SQL語句...當還沒用到數據的時候,就不加載對應的數據!
主要目的就是爲了提升Hibernate的性能,提升執行效率!
User user = (User) session.load(User.class, 1);
System.out.println("________");
System.out.println(user);
複製代碼
咱們能夠在對應的配置文件用一般lazy屬性來設置
關閉懶加載:
<class name="IdCard" table="IdCard" lazy="false">
複製代碼
lazy有三個屬性:
當Session關閉後,就不能使用懶加載了,不然會報出異常
Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session
複製代碼
報出了這個異常,咱們有4種方法解決:
前面咱們已經講解過了一級緩存,一級緩存也就是Session緩存,只在Session的範圍內有效...做用時間就在Session的做用域中,範圍比較小
Hibernate爲咱們提供了二級緩存功能:二級緩存是基於應用程序的緩存,全部的Session均可以使用
Hibernate二級緩存:存儲的是經常使用的類
既然二級緩存是Hibernate自帶的,那麼咱們能夠在hibernate.properties文件中找到對應的信息..
經過配置文件咱們能夠發現,二級緩存默認是不開啓的,須要咱們手動開啓,如下步驟:
在hibernate.cfg.xml文件中開啓二級緩存
<!-- a. 開啓二級緩存 -->
<property name="hibernate.cache.use_second_level_cache">true</property>
複製代碼
指定Hibernate自帶的二級緩存框架就行了
<!-- b. 指定使用哪個緩存框架(默認提供的) -->
<property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
複製代碼
<!-- c. 指定哪一些類,須要加入二級緩存 -->
<class-cache usage="read-write" class="zhongfucheng.aa.Monkey"/>
<class-cache usage="read-only" class="zhongfucheng.aa.Cat"/>
複製代碼
測試:
咱們知道一級緩存是Session的緩存,那麼咱們在測試二級緩存的時候使用兩個Session來測試就行了。若是第二個Session拿到的是緩存數據,那麼就證實二級緩存是有用的。
package zhongfucheng.aa;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;
public class App5 {
public static void main(String[] args) {
//獲取加載配置管理類
Configuration configuration = new Configuration();
//加載類對應的映射文件!
configuration.configure().addClass(Animal.class);
//建立Session工廠對象
SessionFactory factory = configuration.buildSessionFactory();
//獲得Session對象
Session session1 = factory.openSession();
//使用Hibernate操做數據庫,都要開啓事務,獲得事務對象
Transaction transaction = session1.getTransaction();
//開啓事務
transaction.begin();
Monkey monkey = (Monkey) session1.get(Monkey.class,"40283f815be67f42015be67f43240001" );
System.out.println(monkey.getName());
System.out.println("-----------------------");
Session session2 = factory.openSession();
Transaction transaction2 = session2.getTransaction();
transaction2.begin();
Monkey monkey2 = (Monkey) session1.get(Monkey.class, "40283f815be67f42015be67f43240001");
System.out.println(monkey2.getName());
//提交事務
transaction.commit();
transaction2.commit();
//關閉Session
session1.close();
session2.close();
}
}
複製代碼
獲得的是緩存數據!
咱們在把Animal類放進二級緩存的時候,用法爲只讀
也就是說,只能讀取,不能寫入,咱們來看看寫入會怎麼樣:
monkey2.setName("小猴子");
複製代碼
拋出了異常....
usage的屬性有4種:
若是咱們在數據庫查詢的數據是集合...Hibernate默認是沒有爲集合數據設置二級緩存的...所以仍是須要去讀寫數據庫的信息
接下來,咱們就看看把集合設置爲二級緩存是什麼作的:
<!-- 集合緩存[集合緩存的元素對象,也加加入二級緩存] -->
<collection-cache usage="read-write" collection="cn.itcast.b_second_cache.Dept.emps"/>
複製代碼
public void testCache() {
Session session1 = sf.openSession();
session1.beginTransaction();
// a. 查詢一次
Dept dept = (Dept) session1.get(Dept.class, 10);
dept.getEmps().size();// 集合
session1.getTransaction().commit();
session1.close();
System.out.println("------");
// 第二個session
Session session2 = sf.openSession();
session2.beginTransaction();
// a. 查詢一次
dept = (Dept) session2.get(Dept.class, 10); // 二級緩存配置好; 這裏不查詢數據庫
dept.getEmps().size();
session2.getTransaction().commit();
session2.close();
}
複製代碼
list()和iterator()會把數據放在一級緩存,但一級緩存只在Session的做用域中有效...若是想要跨Session來使用,就要設置查詢緩存
咱們在配置文件中還看到了查詢緩存這麼一條配置..
#hibernate.cache.use_query_cache true 【開啓查詢緩存】
複製代碼
也就是說,默認的查詢數據是不放在二級緩存中的,若是咱們想要把查詢出來的數據放到二級緩存,就須要在配置文件中開啓
<!-- 開啓查詢緩存 -->
<property name="hibernate.cache.use_query_cache">true</property>
複製代碼
@Test
public void listCache() {
Session session1 = sf.openSession();
session1.beginTransaction();
// HQL查詢 【setCacheable 指定從二級緩存找,或者是放入二級緩存】
Query q = session1.createQuery("from Dept").setCacheable(true);
System.out.println(q.list());
session1.getTransaction().commit();
session1.close();
Session session2 = sf.openSession();
session2.beginTransaction();
q = session2.createQuery("from Dept").setCacheable(true);
System.out.println(q.list()); // 不查詢數據庫: 須要開啓查詢緩存
session2.getTransaction().commit();
session2.close();
}
複製代碼
若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同窗,能夠關注微信公衆號:Java3y