【大话Hibernate】Hibernate的核心接口和类
Hibernate的核心類和接口一共有6個,分別為:Session、SessionFactory、 Transaction、Query、Criteria和Configuration。這6個核心和類接口在任何開發(fā)中都會用到。通過這些接口,不僅可以對持久化對象進行存取,還能夠進行事務控制。下面對這6個核心接口和類分別加以介紹。
Configuration
Configuration類的作用是對Hibernate進行配置,以及對它進行啟動。在Hibernate的啟動過程中,Configuration 類的實例首先定位映射文檔的位置,讀取這些配置,然后創(chuàng)建一個SessionFactory對象。雖然Configuration類在整個Hibernate項目中只扮演著一個很小的角色,但它是啟動hibernate 時所遇到的每一個對象。簡而言之,它負責管理Hiberante的配置信息,它主要用來加載這些配置文件,如hibernate.cfg.xml文件。
//加載的配置文件 Configuration config = new Configuration().configure("/hibernate/hibernate.cfg.xml"); //還可以加載映射文件 Configuration config = new Configuration().addFile("TRegister.hbm.xml");//方法一 Configuration config = new Configuration().addClass(hibernate.PO.TRegister.class);//方法二 Configuration config = new Configuration().addURL(Configuration.class.getResource("TRegister.hbm.xml"));//方法三SessionFactory
SessionFactory接口負責初始化Hibernate。它充當數(shù)據(jù)存儲源的代理,并負責創(chuàng)建Session對象。這里用到了工廠模式。需要注意的是SessionFactory并不是輕量級的,因為一般情況下,一個項目通常只需要一個SessionFactory就夠,當需要操作多個數(shù)據(jù)庫時,可以為每個數(shù)據(jù)庫指定一個SessionFactory。簡而言之,SessionFactory負責Session實例的創(chuàng)建。可以通過Configuration實例創(chuàng)建。如下例子:
Configuration config = new Configuration().configure("/hibernate/hibernate.cfg.xml");SessionFactory sessionFactory = config.buildSessionFactory();Congifuration對象會根據(jù)當前的配置信息,生成SessionFactory對象。SessionFactory對象一旦構(gòu)造完畢,即被賦予特定的配置信息,即以后配置改變不會影響到創(chuàng)建的SessionFactory對象。如果要把以后的配置信息賦給SessionFactory對象,需要從新的Configuration對象生成新的SessionFactory對象。SessionFactory是純種安全的,可以被多線程調(diào)用以取得Session,而且構(gòu)造SessionFactory很消耗資源,所以多數(shù)情況下一個應用中只初始化一個SessionFactory,為不同的線程提供Session。在實際應用中,當客戶端發(fā)送一個請求線程時,SessionFactory生成一個Session對象來處理客戶請求。
Session
Session接口負責執(zhí)行被持久化對象的CRUD操作(CRUD的任務是完成與數(shù)據(jù)庫的交流,包含了很多常見的SQL語句。)。但需要注意的是Session對象是非線程安全的。同時,Hibernate的session不同于JSP應用中的HttpSession。這里當使用session這個術(shù)語時,其實指的是Hibernate中的session,而以后會將HttpSession對象稱為用戶session。
簡而言之,Session是應用程序與數(shù)據(jù)庫之間的一個會話,是Hibernate運作的中心,持久層操作的基礎(chǔ),相當于JDBC中的Connection。Session對象是通過SessionFactory創(chuàng)建的:
Session session = SessionFactory.openSession();一個持久化類與普通的JavaBean沒有任何區(qū)別,但是它與Session關(guān)聯(lián)后,就具有了持久化能力。當然,這種持久化操作是受Session控制的,即通過Session對象的裝載,保存,創(chuàng)建或查詢持久化對象。Session類的save(),delete()和load()等方法,來分別完成對持久化對象的保存,刪除,修改加載等操作!
Session類方法的用途可以分以下五類:
1:取得持久化對象:get()和load()等方法。
2:持久化對象的保存,更新和刪除:save(),update()saveOrUpdate()和delete()等方法。
3:createQuery()方法:用來從Session生成的Query對象。
4:beginTransaction()方法:從Session對象生成一個Transaction對象。
5:管理Session的方法:isOpen(),flush(),clear(),evict()和close()等方法,其中isOpen()方法用來檢查Session是否仍然打開;flush()用來清理Session緩存,并把緩存中的SQL語句發(fā)送出去,clear()用來清除Session中的所有緩存對象evict()方法來清楚Session緩存中的某個對象;close()關(guān)閉Session。
取得持久化對象的方法:
取得持久化對象的方法主要有g(shù)et()和load(),它們通過主鍵id來取得PO。
public void testDemo(){Session session = HibernateUtil.currentSession();//生成Session實例TRegister tr = (TRegister)session.get(TRegister.class, new Integer(1));//get()方法//TRegister tr = (TRegister)session.load(TRegister.class newInteger(1));//load()方法 System.out.print(tr.getUserName()); }get()與load()的區(qū)別:
先來理解兩個概念:
立即加載對象:當hibernate在從數(shù)據(jù)庫中取得數(shù)據(jù)組裝好一個對象后會立即再從數(shù)據(jù)庫取得數(shù)據(jù)此對象所關(guān)聯(lián)的對象;
延遲加載對象:Hibernate從數(shù)據(jù)庫中取得數(shù)據(jù)組裝好一個對象后,不會立即再從數(shù)據(jù)庫取得數(shù)據(jù)組裝此對象所關(guān)聯(lián)的對象,而是等到需要時, 都會從數(shù)據(jù)庫取得數(shù)據(jù)組裝此對象關(guān)聯(lián)的對象;
get()方法的執(zhí)行順序如下:
a):首先通過id在session緩存中查找對象,如果存在此id的對象,直接將其返回;b):如果在session中查找不到,就在二級緩存中查找,找到后將 其返回;c):如果在session緩存和二級緩存中都找不到此對象,則從數(shù)據(jù)庫中加載有此ID的對象;因此get()方法并不總是導致SQL語句,只有緩存中無此數(shù)據(jù)時,才向數(shù)據(jù)庫發(fā)送SQL!load()與get()的區(qū)別:
1:在立即加載對象時,如果對象存在,load()和get()方法沒有區(qū)別,都可以取得已初始化的對象;但如果當對象不存在且是立即加載時,使用get()方法則返回null,而使用load()則拋出一個異常。因此使用load()方法時,要確認查詢的主鍵ID一定是存在的,從這一點講它沒有g(shù)et方便!2:在延遲加載對象時,get()方法仍然使用立即加載的方式發(fā)送SQL語句,并得到已初始化的對象,而load()方法則根本不發(fā)送SQL語句,它返回一個代理對象,直到這個對象被訪問時才被初始化。持久化對象的保存,更新和刪除方法
save()方法:
session的save()方法將一個PO的屬性取出放入PreparedStatement語句中,然后向數(shù)據(jù)庫中插入一條記錄(或多條記錄,如果有級聯(lián))。
session保存一個對象時,按如下步驟進行:
1:根本配置文件為主鍵id設(shè)置的生成算法,為PO指定一個ID。
2:將 PO對象納入session內(nèi)部緩存(一個Map)內(nèi)。
3:事務提交時,清理緩存,將新對象通過insert語句持久化到數(shù)據(jù)庫中。
如果要為新的PO強制指定一個ID,可以調(diào)用Session的重載方法
save(Objectobj,Serializable id)例:
session.save(tRegister, new Integer(123));在調(diào)用save()方法時,并不立即執(zhí)行SQL語句,而是等到清理完畢緩存時才執(zhí)行。如果在調(diào)用save()方法后又修改了PO的屬性,則Hibernate將會發(fā)送一條insert語句和一條update語句來完成持久化操作,如下:
public ststic void main(String[] args){SessionFactory sf = new Configuration().configure().buildSessionFactory();Session session = sf.openSession();Transaction tx = session.beginTransaction();Person person=new Person();/**為對象設(shè)定一個ID,但注意此ID是無效的,*因為我們在配置文件中ID設(shè)置為Increment,*這樣將被Hibernate的increment算法生成的值覆蓋*/person.setId(001);person.setAge(23);person.setSex("男");person.setUserName("lmb");person.setPassWord("lmb")session.save(person);person.setUserName("Tom");//在save()后又修改了PO的名字tx.commit();session.close();}監(jiān)視上述程序運行會產(chǎn)生二條SQL:
Hibernate:select max(id) from t_register Hibernate:insert into t_register (userName, userPwd, sex, age, id) values (?, ?, ?, ?, ?) Hibernate:update t_register set userName=?, userPwd=?, sex=?, age=? where id=?因此,最好是在對象狀態(tài)穩(wěn)定時再調(diào)用 save()方法,可以少執(zhí)行一條update語句。
調(diào)用save()方法將臨時對象保存到數(shù)據(jù)庫中,對象的臨時狀態(tài)將變?yōu)槌志没癄顟B(tài)。當對象在持久化狀態(tài)時,它一直位于Session緩存中,對它的任何操作在事物提交時都將同步保存到數(shù)據(jù)庫中,因此,對一個已經(jīng)持久化的對象調(diào)用save()或update()方法是沒有意義的,如下:
public ststic void main(String[] args){SessionFactory sf = new Configuration().configure().buildSessionFactory();Session session = sf.openSession();Transaction tx = session.beginTransaction();Person person=new Person();/**為對象設(shè)定一個ID,但注意此ID是無效的,*因為我們在配置文件中ID設(shè)置為Increment,*這樣將被Hibernate的increment算法生成的值覆蓋*/person.setId(001);person.setAge(23);person.setSex("男");person.setUserName("lmb");person.setPassWord("lmb")session.save(person);person.setUserName("Tom");//在save()后又修改了PO的名字session.save(person);//無效session.update();//無效tx.commit();session.close(); }程序運行效果還是和上面的一樣!
update()方法:
Session的update()方法是用來更新脫管對象的。
它的用法如下:
public void updateDemo{public static void main(String[] args){SessionFactory sf = new Configuration().configure().buildSessionFactory();Session session = sf.openSession();Transaction tx = session.beginTransaction();Person person=new Person();person=(Person)session.get(Person.class,new Integer(1));person.setUserName("updated");//更顯脫管對象tx.commit(); } }調(diào)用update()方法時,并不是立即發(fā)送SQL語句,對對象的更新操作將積累起來,在事物提交時由flush()清理緩存,然后發(fā)送一條SQL語句完成全部的更新操作!
saveOrUpdate()方法:
在實際應用中WEB程序員自言自語不會注意一個對象是脫管對象還是臨時對象,而對脫管對象使用save()方法是不對的,對臨時對象使用update()方法也是不對的。為了解決這個問題,便產(chǎn)生saveOrUpdate()方法。
saveOrUpdate()方法首先會判斷該PO是脫管對象還是臨時對象,然后會調(diào)用合適的方法。那么saveOrUpdate()方法如何判斷PO是臨時對象還是脫管對象呢?當滿足下載情況之一時,Hibernate就認定它是臨時對象。
1:在映射表中為<id>元素設(shè)置了unsaved-valu屬性,并且實體對象的ID取值和unsaved-value匹配(默認為null)(注意:int和long型的ID的unsaved-value默認值為0)。
2:在映射文件中為<version>元素設(shè)置了unsaved-value屬性,并且實體對象的version取值和unsaved-value匹配(默認為null)。
delete()方法:
session類的delete()方法負責刪除一個對象(包括持久對象和脫管對象)。
//刪除持久對象 public void deleteDemo{public static void main(String[] args){SessionFactory sf = new Configuration().configure().buildSessionFactory();Session session = sf.openSession();Transaction tx = session.beginTransaction();Person person=new Person();person=(Person)session.get(Person.class,new Integer(1));session.delete(person);//刪除持久對象</span>tx.commit(); } }監(jiān)視運行:
Hibernate: select tregister0_.id as id0_0_, tregister0_.userName asuserName0_0_, tregister0_.userPwd as userPwd0_0_, tregister0_.sex assex0_0_, tregister0_.age as age0_0_ from t_register tregister0_where tregister0_.id=? Hibernate: delete from t_register where id=? //刪除脫管對象 public void deleteDemo2{public static void main(String[] args){SessionFactory sf = new Configuration().configure().buildSessionFactory();Session session = sf.openSession();Transaction tx = session.beginTransaction();Person person=new Person(); person=(Person)session.get(Person.class,new Integer(1));tx.commit(); session.close();//再構(gòu)建一個sessionSession session2=sf.openSession();tx=session2.beginTransaction();session2.delete(person);//刪除脫管對象tx.commit();session.close(); } }監(jiān)視運行:
Hibernate: select tregister0_.id as id0_0_, tregister0_.userName asuserName0_0_, tregister0_.userPwd as userPwd0_0_, tregister0_.sex assex0_0_, tregister0_.age as age0_0_ from t_register tregister0_where tregister0_.id=? Hibernate: delete from t_register where id=?在上述代碼中session2先把tr對象進行關(guān)聯(lián),納入Session緩存中,然后刪除。需要注意的是,在調(diào)用delete()方法時并不是發(fā)送SQL語句,而是在提交事務時,清理了緩存才發(fā)送SQL。使用delete()刪除對象時,會有一些性能上的問題,例如從上面的監(jiān)視中可以看到,當刪除一個對象時,會先調(diào)用get()加載這個對象,然后調(diào)用delete()方法刪除對象,所以發(fā)送了一個多余的selete SQL,所以當刪除大量數(shù)據(jù)時對性能影響就比較大了。為了解決批量刪除的性能問題,常用的辦法是使用批量刪除操作,如下:
//批量刪除public void betchDeleteDemo{public static void main(String[] args){SessionFactory sf = new Configuration().configure().buildSessionFactory();Session session = sf.openSession();Transaction tx = session.beginTransaction();Query q=session.createQuery("delete from Person");q.executeUpdate();//刪除對象 tx.commit(); session.close();} }監(jiān)視運行:
Hibernate: deletefrom t_register只用了一條語句就完成了比量刪除的操作。但它也有問題,批量刪除后的數(shù)據(jù)還會存在緩存中,因此程序查詢時可能得到臟數(shù)據(jù)(得到數(shù)據(jù)庫中已不存在的數(shù)據(jù)),因此在使用批量刪除時,也要經(jīng)窒處世數(shù)據(jù)一致的問題。
Query
Query接口讓你方便地對數(shù)據(jù)庫及持久對象進行查詢,它可以有兩種表達方式:HQL語言或本地數(shù)據(jù)庫的SQL語句。Query經(jīng)常被用來綁定查詢參數(shù)、限制查詢記錄數(shù)量,并最終執(zhí)行查詢操作。在Hibernate3.x中不再使用2.x中的find方法,而是引入了Query接口,用來執(zhí)行HQL。其實在上面的例子中已經(jīng)看出,Query接口可以從session對象生成;
Query接口主要方法有三個:
setXXX()方法:用于設(shè)置HQL中問題或變量的值。
list()方法:返回查詢結(jié)果,并把結(jié)果轉(zhuǎn)換成List對象。
executeUpdate()方法:執(zhí)行更新或刪除名。
setXXX()方法都有二種重載方法:
1:setString(int position,String value):用于設(shè)置HQL中“?”的值:其中position表示?位置,而value自然就是值。如下:
Query query = session.createQuery("from Person person where person.age>? and person.userName like ?");//生成一個Query實例 query.setInteger(0, 18);//設(shè)置第一個問號的值為18 query.setString(1, "%lmb%");//設(shè)置第二個問題的值為%lmb%2:setString(String paraName,Stringvalue);用于設(shè)置HQL中“:”后跟變量的值;其中paraName代表HQL中“:”后跟變量,value為該變量設(shè)置的值。如下:
Query query = session.createQuery("from Person person where person.age>:minAge and person.userName like :userName");//生成一個Query實例 query.setInteger("minAge", 18);//設(shè)置變量minAge值為18 query.setString("userName", "%lmb%");//設(shè)置變量userName值為%lmb%在HQL中使用變量代替問號,然后在setXXX()方法中為該變量設(shè)值。在HQL中使用變量相比問號有以下好處:
1:變量不依賴于它們在查詢字符串中出現(xiàn) 的順序。
2:在同一個查詢中可以多次使用。
3:可讀性好。
list()方法:返回查詢結(jié)果,并把結(jié)果轉(zhuǎn)換成List對象。
public void listDemo{public static void main(String[] args){SessionFactory sf = new Configuration().configure().buildSessionFactory();Session session = sf.openSession();Person person=new Person();Query query=session.createQuery("from Person");java.util.list list=query.list();for(int i=0;i<list.size();i++){person=list.get(i);System.out.println(person);}} }executeUpdate()方法:執(zhí)行更新或刪除名。
Query的executeUpdate()方法用于更新或刪除語句。它常用于批量刪除或批量更新操作,如下:
Query q = session.createQuery("delete from Person"); q.executeUpdate();//刪除對象使用命名查詢(namedQuery):
其實我們還可以不將 HQL寫在程序中,而是寫入映射文件中,這樣在需要的時候很方便!在映射文件中使用<query>標記,把HQL語句放入
nameQueryDemo.java
public void nameQueryDemo{public static void main(String[] args){SessionFactory sf = new Configuration().configure().buildSessionFactory();Session session = sf.openSession();Person person=new Person();Query query=session.getNameQuery("queryUser_byAgeAndName");query.setInteger("minAge",18);query.setString("userName","%x%");List list=query.list(); for(int i=0;i<list.size();i++){person=list.get(i);System.out.println(person.getUserName());} } }Transaction
Transaction接口是一個可選的API,可以選擇不使用這個接口,取而代之的是Hibernate的設(shè)計者自己寫的底層事務處理代碼。 Transaction 接口是對實際事務實現(xiàn)的一個抽象,這些實現(xiàn)包括JDBC的事務、JTA中的UserTransaction、甚至可以是CORBA事務。之所以這樣設(shè)計是能讓開發(fā)者能夠使用一個統(tǒng)一事務的操作界面,使得自己的項目可以在不同的環(huán)境和容器之間方便地移植。簡而言之,該接口允許應用等量齊觀定義工作單元,同時又可調(diào)用JTA或JDBC執(zhí)行事物管理。它的運行與Session接口相關(guān),可調(diào)用Session的beginTransaction()方法生成一個Transaction實例。一個Session實例可以與多個Transaction實例相關(guān)聯(lián),但是一個特定的Session實例在任何時候必須與至少一個未提交的Transaction實例相關(guān)聯(lián)。
Transaction接口常用如下方法:
1:commit();提交相關(guān)聯(lián)的Session實例。
2:rollback();撤銷事物操作。
3:wasCommitted();事物是否提交。
總結(jié)
以上是生活随笔為你收集整理的【大话Hibernate】Hibernate的核心接口和类的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Hibernate】getHibern
- 下一篇: 【大话Hibernate】hiberna