1.為什么要使用Hibernate開發你的項目呢?Hibernate的開發流程是怎么樣的?
①.對JDBC訪問數據庫的代碼做了封裝,大大簡化了數據訪問層繁瑣的重復性代碼。
② .Hibernate 是一個基於JDBC的主流持久化框架,是一個優秀的ORM 實現。他很大程度 的簡化DAO層的編碼工作
③ .hibernate 的性能非常好,因為它是個輕量級框架。映射的靈活性很出色。它支持各種關系數據庫,從一對一到多對多的各種復雜關系。
2.什么是延遲加載?
3.說一下hibernate的緩存機制
(1)hibernate支持兩個級別的緩存,默認只支持一級緩存;
(2)每個Session內部自帶一個一級緩存;
(3)某個Session被關閉時,其對應的一級緩存自動清除;
(1) 二級緩存獨立於session,默認不開啟;
4.Hibernate的查詢方式有哪些?
5.如何優化Hibernate?
6.Hibernate中GET和LOAD的區別?
7.說說在 hibernate中使用Integer做映射和使用int做映射之間有什么差別?
Integer是對象. code=null; 對象可以為空.
int 是普通類型, 不可能=null.
你沒理由hbm.xml里寫 Integer,類里卻寫int
8.SQL和HQL有什么區別?
hql 面向對象查詢
hql:from 后面跟的 類名+類對象 where 后 用 對象的屬性做條件
sql:from 后面跟的是表名 where 后 用表中字段做條件
查詢
在Hibernate中使用查詢時,一般使用Hql查詢語句。
HQL(Hibernate Query Language),即Hibernate的查詢語言跟SQL非常相像。不過HQL與SQL的最根本的區別,就是它是面向對象的。
使用HQL時需要注意以下幾點:
1.大小寫敏感
因為HQL是面向對象的,而對象類的名稱和屬性都是大小寫敏感的,所以HQL是大小寫敏感的。HQL語句:from Cat as cat where cat.id > 1;與from Cat as cat where cat.ID > 1;是不一樣的,這點與SQL不同。
from Cat,該句返回Cat對象實例,開發人員也可以給其加上別名,eg. from Cat as cat,對於多表查詢的情況,可參考如下:from Cat as cat, Dog as dog其它方面都與SQL類似,在此不再贅述。
9.Hibernate的分頁查詢
q.setMaxResults(100);;
List l = q.list();;
q.setFirstResult(20000);;
10.Hibernate中Java對象的狀態以及對應的特征有哪些?
持久化對象PO和OID
PO=POJO + hbm映射配置
編寫規則
①必須提供無參數public構造器
②所有屬性private,提供public的getter和setter方法
③必須提供標識屬性,與數據表中主鍵對應,例如Customer類 id屬性
④PO類屬性應盡量使用基本數據類型的包裝類型(區分空值) 例如int---Integer long---Long
⑤不要用final修飾(將無法生成代理對象進行優化)
* 例如內存中有兩個PO對象,只要具有相同 OID, Hibernate認為同一個對象
* Hibernate 不允許緩存同樣OID 的兩個不同對象
②持久態:存在持久化標識OID,與當前session有關聯,並且相關聯的session沒有關閉 ,並且事務未提交
③脫管態(離線態、游離態):存在持久化標識OID,但沒有與當前session關聯,脫管狀態改變hibernate 不能檢測到
// 獲得Session
Session session =HibernateUtils.openSession();
// 開啟事務
Transaction transaction = session.beginTransaction();
Book book =newBook();// 瞬時態(沒有OID,未與Session關聯)
book.setName("hibernate精通");
book.setPrice(56d);
session.save(book);// 持久態(具有OID,與Session關聯)
// 提交事務,關閉Session
transaction.commit();
session.close();
System.out.println(book.getId());// 脫管態(具有 OID,與Session斷開關聯)
11.Hibernate中怎樣處理事務?
Hibernate是對JDBC的輕量級對象封裝,Hibernate本身是不具備Transaction 處理功能的,Hibernate的Transaction實際上是底層的JDBC Transaction的封裝,或者是JTA Transaction的封裝,下面我們詳細的分析:
Hibernate可以配置為JDBCTransaction或者是JTATransaction,這取決於你在hibernate.properties中的配置:
#hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
#hibernate.transaction.factory_class net.sf.hibernate.transaction.JDBCTransactionFactory
hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
將使用JTATransaction,不管你准備讓Hibernate使用JDBCTransaction,還是JTATransaction,我的忠告就是什么都不配,將讓它保持默認狀態,如下:
#hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
#hibernate.transaction.factory_class net.sf.hibernate.transaction.JDBCTransactionFactory
一、JDBC Transaction
看看使用JDBC Transaction的時候我們的代碼例子:
Session session = sf.openSession();
Transaction tx = session.beginTransactioin();
...
session.flush();
tx.commit();
session.close();
Hibernate2.0.3源代碼中的類
net.sf.hibernate.transaction.JDBCTransaction:
public void begin() throws HibernateException {
...
if (toggleAutoCommit) session.connection().setAutoCommit(false);
...
}
再來看
public void commit() throws HibernateException {
...
try {
if ( session.getFlushMode()!=FlushMode.NEVER ) session.flush();
try {
session.connection().commit();
committed = true;
}
...
toggleAutoCommit();
}
Connection conn = ...; <--- session = sf.openSession();
conn.setAutoCommit(false); <--- tx = session.beginTransactioin();
... <--- ...
conn.commit(); <--- tx.commit(); (對應左邊的兩句)
conn.setAutoCommit(true);
conn.close(); <--- session.close();
12.簡單的介紹一下Hibernate的核心API?
//方式一:
去src 讀取 hibernate.properties 屬性配置文件
Configuration cfg =newConfiguration();
//方式二:去src讀取 hibernate.cfg.xml
Configuration cfg =newConfiguration().configure();
Configuration cfg =newConfiguration().configure("自定義xml文件");去src 加載指定文件
org.hibernate.MappingException:Unknown entity: cn.itcast.domain.Customer
//方式一:
configuration.addResource("cn/itcast/domain/Customer.hbm.xml");加載hbm文件
//方式二:
configuration.addClass(Customer.class);加載Class,自動搜索hbm映射文件
//預定義SQL語句
<sql-queryname="login">
<![CDATA[select * from user where username= ? and password =?]]>
</sql-query>
save 完成插入
update 完成修改
delete完成刪除
get/load 根據主鍵字段查詢
createQuery、 createSQLQuery 創建查詢對象Query接收HQL,SQLQuery接收SQL
createCriteria() 面向對象條件查詢
//默認false
<property name="hibernate.connection.autocommit">false</property> 事務不提交
<propertyname="hibernate.connection.autocommit">true</property> 事務提交
開發代碼步驟
獲得HibernateSession對象
編寫HQL語句
調用session.createQuery 創建查詢對象
如果HQL語句包含參數,則調用Query的setXXX設置參數
調用Query對象的list()或uniqueResult()方法執行查詢
13.update與saveOrUpdate有什么區別?
update() 如果是對一個已經存在的托管對象進行更新那么肯定是要使用update()方法了,數據中有這個對象。
saveOrUpdate() 這個方法是更新或者插入,有主鍵就執行更新,如果沒有主鍵就執行插入。【此方法慎用】
有兩張表,表A和表B,這兩張表的主鍵都是一樣的,例如都是MASTER_ID,同時對應的BO里面屬性都是masterID,現在要執行的操作是,以 MASTER_ID為條件將表A中的數據查詢出來,然后將部分值插入到表B中,然后再更新表B,在查詢表A后,session中已經存在masterID 了,這個時候再去對表B進行savaOrUpdate的時候,Hibernate會發現session中已經存在masterID了,所以執行的就是 update,但是實際上表B中根本不存在masterID這個值,當你執行完查詢數據庫的時候會發現沒有插入數據,像這種情況,就得先用 masterID對表B進行查詢,當返回的BO為NULL時,new一個新BO然后再進行插入,這個時候用到的就是createbo了。
14.Hibernate的inverse屬性的作用?
inverse 決定是否把對對象中集合的改動反映到數據庫中,所以inverse只對集合起作用,也就是只對one-to-many或many-to-many有效(因為只有這兩種關聯關系包含集合,而one-to-one和many-to-one只含有關系對方的一個引用)。
cascade決定是否把對對象的改動反映到數據庫中,所以cascade對所有的關聯關系都起作用(因為關聯關系就是指對象之間的關聯關系)。
2.inverse 屬性 :inverse所描述的是對象之間關聯關系的維護方式。
inverse只存在於集合標記的元素中 。Hibernate提供的集合元素包括<set/> <map/> <list/> <array /> <bag />
Inverse屬性的作用是:是否將對集合對象的修改反映到數據庫中。 inverse屬性的默認值為false,表示對集合對象的修改會被反映到數據庫中;inverse=false 的為主動方,由主動方負責維護關聯關系。 inverse=”true” 表示對集合對象的修改不會被反映到數據庫中。 為了維持兩個實體類(表)的關系,而添加的一些屬性,該屬性可能在兩個實體類(表)或者在一個獨立的表里面,這個要看這雙方直接的對應關系了: 這里的維護指的是當主控放進行增刪改查操作時,會同時對關聯關系進行對應的更新。
一對多: 該屬性在多的一方。應該在一方的設置 inverse=true ,多的一方設置 inverse=false(多的一方也可以不設置inverse屬性,因為默認值是false),這說明關聯關系由多的一方來維護。如果要一方維護關 系,就會使在插入或是刪除"一"方時去update"多"方的每一個與這個"一"的對象有關系的對象。而如果讓"多"方面維護關系時就不會有update 操作,因為關系就是在多方的對象中的,直指插入或是刪除多方對象就行了。顯然這樣做的話,會減少很多操作,提高了效率。
多對多: 屬性在獨立表中。inverse屬性的默認值為false。在多對多關聯關系中,關系的兩端 inverse不能都設為false,即默認的情況是不對的,如果都設為false,在做插入操作時會導致在關系表中插入兩次關系。也不能都設為 true,如果都設為true,任何操作都不會觸發對關系表的操作。因此在任意一方設置inverse=true,另一方inverse=false。
一對一: 其實是一對多的一個特例,inverse 的設置也是一樣的,主要還是看關聯關系的屬性在哪一方,這一方的inverse=false。
多對一: 也就是一對多的反過來,沒什么區別。
3.cascade 屬性
級聯操作:指當主控方執行某項操作時,是否要對被關聯方也執行相同的操作。
注意:<one-to-many />和 <many-to-many />是用在集合標記內部的,所以是不需要cascade屬性的。
4.inverse和cascade的區別
作用的范圍不同:
Inverse是設置在集合元素中的。
Cascade對於所有涉及到關聯的元素都有效。
<many-to-one/><ont-to-many/>沒有inverse屬性,但有cascade屬性
執行的策略不同
Inverse 會首先判斷集合的變化情況,然后針對變化執行相應的處理。
Cascade 是直接對集合中每個元素執行相應的處理
執行的時機不同
Inverse是在執行SQL語句之前判斷是否要執行該SQL語句
Cascade則在主控方發生操作時用來判斷是否要進行級聯操作
執行的目標不同
Inverse對於<ont-to-many>和<many-to-many>處理方式不相同。
對於<ont-to-many>,inverse所處理的是對被關聯表進行修改操作。
對於<many-to-many>,inverse所處理的則是中間關聯表
Cascade不會區分這兩種關系的差別,所做的操作都是針對被關聯的對象。
總結:
<one-to-many>
<one-to-many>中,建議inverse=”true”,由“many”方來進行關聯關系的維護
<many-to-many>中,只設置其中一方inverse=”false”,或雙方都不設置
Cascade,通常情況下都不會使用。特別是刪除,一定要慎重。
操作建議:
many-to-many關聯關系中,一端設置inverse=”false”,另一端設置為inverse=”true”。在one-to-many關聯關系中,設置inverse=”true”,由多端來維護關系表
Hibernate一級緩存相關問題
*private transient ActionQueue actionQueue; ----行動隊列(標記數據活動)
*private transient StatefulPersistenceContext persistenceContext;----持久化上下文
Book book =(Book) session.get(Book.class,1);// 第一次查詢,緩存中沒有
System.out.println(book);
Book book2 =(Book) session.get(Book.class,1);// 因為第一次查詢,對象已經被放入1級緩存,不會查詢數據
System.out.println(book2);
*生成一條SQL語句,返回同一個對象,第一次查詢生成SQL,查詢對象,將對象放入一級緩存,第二次查詢,直接從一級緩存獲得
* 測試快照區的使用
*/
@Test
publicvoid demo3(){
// 獲得Session
Session session =HibernateUtils.openSession();
// 開啟事務
Transaction transaction = session.beginTransaction();
// 查詢id 為1 的圖書對象
Book book =(Book) session.get(Book.class,1);// 第一次查詢,將對象加入一級緩存
System.out.println(book);
book.setName("深入淺出Hibernate技術");// 修改書名(一級緩存被修改,自動update)
// 沒有手動執行update,因為快照區原因,自動更新
// 提交事務,關閉Session
transaction.commit();
session.close();
@Test
// Session 對於 一級緩存操作
publicvoid demo4(){
// 獲得Session
Session session =HibernateUtils.openSession();
// 開啟事務
Transaction transaction = session.beginTransaction();
// 查詢id 為1 的圖書對象
Book book =(Book) session.get(Book.class,1);// 第一次查詢,將對象加入一級緩存
System.out.println(book);
// book.setPrice(80d); // 修改一級緩存數據
// 將緩存內容同步到數據庫
// session.flush();
// 清除一級緩存所有數據
// session.clear();
// 清除一級緩存中 指定對象
// session.evict(book);
book.setPrice(30d);// 一級緩存改變
session.refresh(book);// 用數據庫內容 覆蓋快照區和一級緩存
// 提交事務,關閉Session
transaction.commit();
session.close();
}
@Test
// 理解 FlushMode作用
publicvoid demo5(){
// 獲得Session
Session session =HibernateUtils.openSession();
// 設置 flushMode
session.setFlushMode(FlushMode.MANUAL);
// 開啟事務
Transaction transaction = session.beginTransaction();
// 查詢id 為1 的圖書對象
Book book =(Book) session.get(Book.class,1);// 第一次查詢,將對象加入一級緩存
System.out.println(book);
book.setPrice(1000d);// 修改價格
session.createQuery("from Book").list();// 查詢所有圖書 (AUTO 級別 flush)
// 提交事務,關閉Session
transaction.commit();// (COMMIT 級別 flush)
// session.flush(); // MANUAL 級別 flush
session.close();
}
@Test
// 脫管對象更新
publicvoid demo6(){
// 獲得Session
Session session =HibernateUtils.openSession();
// 開啟事務
Transaction transaction = session.beginTransaction();
Book book =newBook();// 瞬時
book.setId(1);// 脫管
book.setName("java入門");
book.setPrice(40d);
session.update(book);// 持久
session.flush();
// book.setPrice(50d);
// 提交事務,關閉Session
transaction.commit();
session.close();
}
<classname="cn.itcast.domain.firstcache.Book"table="book"catalog="hibernate3day2"select-before-update="true">
@Test
// 一級緩存 存在兩個相同OID 持久態對象 報錯
publicvoid demo7(){
// 獲得Session
Session session =HibernateUtils.openSession();
// 開啟事務
Transaction transaction = session.beginTransaction();
// 查詢
// Book b = (Book) session.get(Book.class, 1); // 持久
Book book =newBook();// 瞬時
book.setId(1);// 脫管
book.setName("java入門");
book.setPrice(50d);
session.update(book);// 持久
// 提交事務,關閉Session
transaction.commit();
session.close();
}
@Test
// PO對象,OID為 hbm文件 配置 unsaved-value 也是瞬時對象, saveOrUpdate 執行 save操作
publicvoid demo8(){
// 獲得Session
Session session =HibernateUtils.openSession();
// 開啟事務
Transaction transaction = session.beginTransaction();
Book book =newBook();// 瞬時
book.setId(-1);// 存在OID , -1是unsaved-value 也是瞬時
book.setName("xxx");
book.setPrice(100d);
session.saveOrUpdate(book);
// 提交事務,關閉Session
transaction.commit();
session.close();
}
Hibernate二級緩存相關問題
緩存好處: 將數據庫或者硬盤數據,保存在內存中,減少數據庫查詢次數,減少硬盤交互,提高檢索效率
hibernate 共有兩個級別的緩存
* 一級緩存,保存Session中, 事務范圍的緩存
* 二級緩存,保存SessionFactory ,進程范圍的緩存
SessionFacoty 兩部分緩存
內置 :Hibernate 自帶的, 不可卸載. 通常在 Hibernate 的初始化階段, Hibernate 會把映射元數據和預定義的 SQL 語句放到 SessionFactory 的緩存中, 映射元數據是映射文件中數據的復制, 而預定義 SQL 語句時 Hibernate 根據映射元數據推到出來的. 該內置緩存是只讀的.
外置 :一個可配置的緩存插件. 在默認情況下, SessionFactory 不會啟用這個緩存插件. 外置緩存中的數據是數據庫數據的復制, 外置緩存的物理介質可以是內存或硬盤,必須引入第三方緩存插件才能使用。
* 更新時間戳區域
* 查詢緩存區域
** 一級緩存的操作會同步到二級緩存
更新時間戳區域
作用:記錄數據最后更新時間,確保緩存數據是有效的
Hibernate 提供了和查詢相關的緩存區域:
時間戳緩存區域存放了對於查詢結果相關的表進行插入 , 更新或刪除操作的時間戳. Hibernate 通過時間戳緩存區域來判斷被緩存的查詢結果是否過期, 其運行過程如下 :
T1 時刻執行查詢操作, 把查詢結果存放在 QueryCache 區域, 記錄該區域的時間戳為 T1
T2 時刻對查詢結果相關的表進行更新操作, Hibernate 把 T2 時刻存放在 UpdateTimestampCache 區域.
T3 時刻執行查詢結果前, 先比較 QueryCache 區域的時間戳和 UpdateTimestampCache 區域的時間戳, 若 T2 >T1, 那么就丟棄原先存放在 QueryCache 區域的查詢結果, 重新到數據庫中查詢數據, 再把結果存放到 QueryCache 區域; 若 T2 < T1, 直接從 QueryCache 中獲得查詢結果。
* 二級緩存緩存數據都是類對象數據,數據都是緩存在 "類緩存區域" ,二級緩存緩存PO類對象,條件(key)是id
查詢緩存適用場合:
**應用程序運行時經常使用查詢語句
**很少對與查詢語句檢索到的數據進行插入, 刪除和更新操作
如果查詢條件不是id查詢, 緩存數據不是PO類完整對象 =====> 不適合使用二級緩存
查詢緩存: 緩存的是查詢數據結果, key是查詢生成SQL語句 , 查詢緩存比二級緩存功能更加強大
2)啟用查詢緩存 hibernate.cfg.xml
<property name="hibernate.cache.use_query_cache">true</property>
query.setCacheable(true);
transactional : 提供Repeatable Read事務隔離級別,緩存支持事務,發生異常的時候,緩存也能夠回滾
read-write : 提供Read Committed事務隔離級別,更新緩存的時候會鎖定緩存中的數據
nonstrict-read-write :導致臟讀, 很少使用
read-only : 數據不允許修改,只能查詢
* 很少被修改,不是很重要,允許偶爾的並發問題, 適合放入二級緩存。考慮因素(二級緩存的監控【后面學習】,它是是否采用二級緩存主要參考指標)
* OSCache
可作為進程范圍內的緩存, 存放數據的物理介質可以是內存或硬盤, 提供了豐富的緩存數據過期策略, 對 Hibernate 的查詢緩存提供了支持
* SwarmCache
可作為集群范圍內的緩存, 但不支持 Hibernate 的查詢緩存
* JBossCache
可作為集群范圍內的緩存, 支持 Hibernate 的查詢緩存