<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    注銷

    注銷

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      112 隨筆 :: 7 文章 :: 18 評論 :: 0 Trackbacks
    持久層的組成
        這一節的名字應該換成“基于Hibernate的持久層的組成”更合適一點,可是它太長了。既然Hibernate是用來開發持久層,那么我先介紹一下這個持久層中的各個元素。
    1.    POJO:Plain Old Java Object,你可以把它看作是簡單的JavaBean。一般說來,一張數據庫表對應一個POJO,也就是對象/關系的一一映射。
    2.    DAO:對于每一個POJO,一般都有一個DAO與之對應,承擔所有關于該POJO的訪問控制。實際上也就是控制了對數據庫中一張表的訪問控制。
    3.    *.hbm.xml文件:這個文件定義了POJO和數據庫中的表是如何映射的,比如POJO中的字段對應數據庫表中的哪個字段等等。一般每個映射都用單獨的文件來描述,也就是有一個POJO就有一個*.hbm.xml文件。
    4.    *.cfg.xml文件:這個文件定義了Hibernate的基本信息,比如數據庫驅動,用戶名,密碼等等連接信息,也包括了所有要用的*.hbm.xml文件,在初始化的時候,Hibernate會讀取這個文件來找相應的映射文件完成對象/關系。
    我們還是以上文的例子來詳細描述一下這里提到的各個元素的內容。
    1.    Student.java:
    代碼片段4:
    1. public class Student  implements java.io.Serializable 
    2. {
    3.     private String id;
    4.     private String name;
    5.     private Set courseSelections = new HashSet(0);
    6.     public Student() 
    7.     {
    8.     }
    9.     public String getId() 
    10.     {
    11.         return this.id;
    12.     }
    13.     
    14.     public void setId(String id) 
    15.     {
    16.         this.id = id;
    17.     }
    18.     public String getName() 
    19.     {
    20.         return this.name;
    21.     }
    22.     
    23.     public void setName(String name) 
    24.     {
    25.         this.name = name;
    26.     }
    27.     public Set getCourseSelections() 
    28.     {
    29.         return this.courseSelections;
    30.     }
    31.     
    32.     public void setCourseSelections(Set courseSelections) 
    33.     {
    34.         this.courseSelections = courseSelections;
    35.     }
    36. }

    這個類就是一個POJO,你可以很明顯的看出來它就是一個JavaBean。我想解釋它的courseSelection字段。很顯然,在數據庫表student中,沒有這個字段。這里的這個字段是因為一個外鍵引用,course_selection的student_id是一個外鍵,引用了student表中的id字段。那么在Student類中courseSelection來記錄這樣的外鍵關系,也就是說,當我們獲取了Student對象以后,就可以直接獲取他的選課記錄,這樣就為上層的調用提供了很大的方便。這里有點模糊沒關系,我在介紹映射定義文件(*.hbm.xml)的時候還會提到這個問題。
    2.    StudentDAO.java
    代碼片段5:
    1. public class StudentDAO 
    2. {
    3.     Session session;
    4.     public StudentDAO()
    5.     {
    6.         Configuration cfg = new Configuration();
    7.         cfg.configure("/hibernate.cfg.xml");
    8.         SessionFactory sessionFactory = cfg.buildSessionFactory();
    9.         session = sessionFactory.openSession();
    10.     }
    11.     
    12.     public void save(Student transientInstance) 
    13.     {
    14.         session.save(transientInstance);
    15.     }
    16.     
    17.     public void delete(Student persistentInstance) 
    18.     {
    19.         session.delete(persistentInstance);
    20.     }
    21.     
    22.     public Student findById(java.lang.String id) 
    23.     {
    24.         List list = session.createCriteria(Student.class).add(
    25. Expression.eq("id", id)).list();
    26.         if (list.size() > 0) 
    27.         {
    28.             return (Student)list.get(0);
    29.         }
    30.         return null;
    31.     }
    32. }

    這里的構造函數是用來啟動Hibernate,并獲取session。打開一個session就相當于打開了一個數據庫連接,然后我們就可以對這個session進行操作,完成數據庫操作,完全不用寫SQL語句。我這里Hibernate的啟動方式寫的很不規范,系統應該只需要完成一次Hibernate啟動就可以在不同的DAO中使用,我把它寫在構造函數里面純粹是為了簡化演示代碼。
    你可以看到save和delete方法都很簡單直接對對象操作,而findById就有些麻煩,因為這里有一個查詢過程在里面。Hibernate里面查詢可以用Criteria這個類來完成,我們也常用Hibernate獨有的HQL(Hibernate Query Language)來完成查詢。當然Hibernate也是支持原生SQL的。關于查詢的詳細信息請參考其他文章或書籍,我只是演示一個流程,介紹一些概念。
    3.    Student.hbm.xml
    代碼片段6:
    1. <hibernate-mapping>
    2.     <class name="Student" table="STUDENT">
    3.         <id name="id" type="string">
    4.             <column name="ID" length="10" />
    5.             <generator class="assigned" />
    6.         </id>
    7.         <property name="name" type="string">
    8.             <column name="NAME" not-null="true" />
    9.         </property>
    10.         <set name="courseSelections" inverse="true">
    11.             <key>
    12.                 <column name="STUDENT_ID" length="10" 
    13. not-null="true" />
    14.             </key>
    15.             <one-to-many class="CourseSelection" />
    16.         </set>
    17.     </class>
    18. </hibernate-mapping>

    這個文件定義了Student類和Student表是如何映射的。class元素定義了Sudent類和STUDENT表映射,然后就定義了各個屬性是如何映射的。如果一個屬性是數據庫的key,那么會用id標簽來定義,column定義了當前類的屬性和數據庫中的哪個字段對應,generator是id特有的。一般來說id是自增的,由于我的數據庫是用的Oracle,它沒有自增字段,要實現自增必須用Sequence,這超出了本文的范圍,所以我就用assigned來簡化示例代碼。assigned表示id是用戶給定的。
    有一個比較特別的標簽是set,它對應著數據庫中的外鍵關系,上文我提到的通過Student對象可以獲得所有相關的選課記錄就是通過這里的定義實現的。name屬性對應了Student類中的字段名,key表示哪個字段是外鍵,one-to-many表示Student和CourseSelection是一對多關系,這和事實相符。類似的還有many-to-one,many-to-many,不過這些都不常用,我不介紹了。Hibernate根據這個映射定義文件,在實例化一個POJO(比如Student)的時候,會自動的把定義過映射的屬性用數據庫中的數據填充,set也包括在內。
    4.    hibernate.cfg.xml
    代碼片段7:
    1. <hibernate-configuration>
    2.     <session-factory>
    3.         <property name="connection.username">test</property>
    4.         <property name="connection.url">
    5. jdbc:oracle:thin:@10.85.33.199:1521:glee</property>
    6.         <property name="dialect">
    7. org.hibernate.dialect.Oracle9Dialect</property>
    8.         <property name="connection.password">test</property>
    9.         <property name="connection.driver_class">
    10. oracle.jdbc.OracleDriver</property>
    11.         <mapping resource="Student.hbm.xml"></mapping>
    12.         <mapping resource="CourseSelection.hbm.xml"></mapping>
    13.         <mapping resource="Course.hbm.xml"></mapping>
    14.     </session-factory>
    15. </hibernate-configuration>

    這個文件我不解釋了,自己看吧。結合上文StudentDAO的例子,我想你應該能看明白。
    看了這么多,或許你會有點頭皮發麻,POJO,DAO,配置文件...好像要寫的東西還是很多。值得慶幸的是現在Hibernate已經發展的比較成熟了,有很多工具來幫助我們完成這些工作,比如MiddleGen,Hibernate Synchronizer等等。我使用的開發工具是Eclipse+MyEclipse,我所要做的只是把數據庫表建好,然后MyEclipse提供的工具會自動根據數據庫表生成POJO,DAO,*.hbm.xml,甚至hibernate.cfg.xml都是自動完成的(前提是MyEclipse知道你的數據庫連接信息)。我并不打算介紹如何用IDE來開發Hibernate,你可以參考IDE的幫助文檔。
    到這里為止,使用Hibernate進行開發的基本組成元素我都介紹好了,強烈建議你馬上實踐一遍,即使有些不理解,也先依葫蘆畫瓢一個。對了,別忘了把Hibernate的包down下來放到classpath里面。

    三、Session與SessionFactory
    Session可以說是Hibernate的核心,Hibernate對外暴露的接口就是Session。所以我這里講一下有關Session的常用函數和特性。
    在講Session之前,我想先提一下SessionFactory,這個東西不復雜,只要配置好就行了。顧名思義,SessionFactory就是用來創建Session的。SessionFactory是線程安全的,也就是說對于同一個數據庫的所有操作共享一個SessionFactory就行了。回頭看代碼片段5,我們可以看到SessionFactory的常用配置方式。
    代碼片段8:
    1. Configuration cfg = new Configuration();
    2. cfg.configure("/hibernate.cfg.xml");
    3. SessionFactory sessionFactory = cfg.buildSessionFactory();

    我們通過Configuration來讀取配置文件,然后就可以創建SessionFactory,這段代碼在    所有系統中都大同小異,一般就是xml配置文件的名字不一樣,所以也沒什么好說的。
    當我們有了SessionFactory以后就可以獲取Session了。調用SessionFactory.openSession()就會返回一個Session實例,然后我們操作這個Session來訪問數據庫。值得一提的是Session并不是線程安全的,也就是每一個線程都必須有自己的Session。所以我們一般通過以下方法來獲取和關閉Session:
    代碼片段9:
    1. public static Session currentSession() throws HibernateException 
    2.     {
    3.         Session session = (Session) threadLocal.get();
    4.         if (session == null || !session.isOpen()) 
    5.         {
    6.             if (sessionFactory == null
    7.             {
    8.                 try 
    9.                 {
    10.                     cfg.configure(CONFIG_FILE_LOCATION);
    11.                     sessionFactory = cfg.buildSessionFactory();
    12.                 } 
    13.                 catch (Exception e) 
    14.                 {
    15.                     e.printStackTrace();
    16.                 }
    17.             }
    18.             session = (sessionFactory != null) ?
    19.                  sessionFactory.openSession(): null;
    20.             threadLocal.set(session);
    21.         }
    22.         return session;
    23. }
    24. public static void closeSession() throws HibernateException 
    25.     {
    26.         Session session = (Session) threadLocal.get();
    27.         threadLocal.set(null);
    28.         if (session != null
    29.         {
    30.             session.close();
    31.         }
    32. }

    可以看到,我們通過threadLocal來保存每個線程的session,這樣就保證了各個線程之    間的互不干擾,也保證了系統只有一個SessionFactory實例(對于大多數應用來說已經    足夠了)。如果你使用MyEclipse進行開發的話,它會自動生成一個    HibernateSessionFactory.java,其中就包含了以上代碼。
    好了,現在我們已經獲得了Session,下面我來介紹以下Session的常用函數,這些函數都有很多重載函數,我只介紹以下大概是干嘛的,不一一解釋,詳細信息你可以查看Hibernate的API。
    1.Session.get(),獲取某個類的實例,一般都是通過id來獲取比如
    Session.get(Student.class, "0361095");
    這句話的意思就是獲取id(primary key)為“0361095”的Student對象。這里要注    意的是第二個參數必須是Object,也就是說,如果是long類型的1,那么必須轉換    成new Long(1)再傳入。
    2.Session.load(),用法和意義都和get一樣,不過它們還是有點區別,我稍后解釋。
    3.Session.save(),將某個實例保存到數據庫中去(往往在數據庫中形成一條新的記錄)。
    4.Session.update(),更新某個實例,這個實例必須和數據庫中有對應,否則會報錯。
    5.Session.delete(),刪除某個實例,也就是刪除這個實例對應的數據表中的數據。
    6.Session.saveOrUpdate(),保存或者更新某個實例,調用這個方法你就不用去關心到        底是save還是update了,它會自己判斷,然后調用相應的函數。其實save和update        涉及到實體對象生命周期中的三種狀態,這個比較重要,我在后面會單獨講的。
    對于get和load的區別,很難講清楚,這里涉及到Hibernate的緩存機制,是一個非常    復雜的話題,我不打算深入討論這個內容。簡單的來講,Session實現了Hibernate的一    級緩存,SessionFactory實現了Hibernate的二級緩存。load方法會先查找一級緩存再查    找二級緩存,最后再去數據庫中找,而get只會查找一級緩存,然后就去數據庫中找了。    這只是是get和load的一個區別,另外的區別如果你有興趣的話自己去google吧。關于Hibernate的緩存機制,如果你只是一般用用Hibernate的話沒有必要深入研究,就當它不存在好了,get和load到底用哪個也不用非常講究,如果你用工具生成DAO的話,    生成的代碼用什么就用什么吧。

    四、關鍵概念的理解
    在使用Hibernate進行開發的時候有幾個概念在我看來是必須理解的,否則在開發的時候會遇到很多問題而摸不著頭腦。
    1.Lazy loading,懶加載(延遲加載)
    這個技術在很多地方被應用,比如Eclipse的插件管理也是用的延遲加載。在Hibernate中,所謂延遲加載就是返回一個POJO但是某些數據(往往是實體類型或者Set類型)并沒有被真正的被填充,直到POJO的某個字段真正被引用的時候才從數據庫中讀取相應的數據來填充POJO中的字段。這樣就能有效的避免很多不必要的數據庫操作,因為POJO的有些數據我們并不需要,而且數據庫操作是很費時間的。在Hibernate2中,默認是非延遲加載的,而在Hibernate3中,默認就是延遲加載了。
    如果使用了延遲加載,那么在讀取數據的時候有一個問題必須注意,那就是在數據真正被加載之前,Session不能被關閉。你可以回頭看一下代碼片段5,我在構造函數里面open了session以后就沒有關閉這個session,所以我在使用的時候沒有什么問題,但這樣總占著數據庫連接也不好,用好了應該及時關閉給別人用。我上文給的例子中沒有關閉Session的代碼,要加的話給DAO加一個方法調用Session.close(),然后在代碼片段1中的return之前調用這個方法就行了。
    Hibernate的延遲加載機制遠不是這么簡單,但是普通的應用沒有必要去深究這些東西,了解這么多就夠了。

    2. Object lifecycle,對象生命周期
    在Hibernate中,對象分為三種狀態,Transient(自由狀態)、Persistent(持久狀態),Detached(游離狀態),下面我分別解釋一下。
    1、自由狀態:所謂自由狀態就是說這個對象是自由的,與Hibernate無關,比       如:
    Student student = new Student();
        student.setId("0361095");
                    這里的student就是一個普通的對象與hibernate無關,稱為自由狀態。

    2、持久狀態:所謂持久狀態就是指對象和數據庫中的數據(持久狀態的數據)       有關聯,也就是說對象被Hibernate所管理了,比如:
    session.save(student);
       這樣student對象就從自由狀態變為持久狀態了。持久狀態的對象在Session       與數據庫中的數據進行同步時(比如commit)會把數據更新到數據庫。而         其他狀態的則不會。我覺得可以這樣來理解持久狀態,可以看成Hibernate       也擁有一份對象的引用,那么如果你對持久狀態對象的屬性進行更改的話,       Hibernate看到的對象的狀態也更改了,而Hibernate所看到的對象和數據       庫中的數據是等價的。也正是這樣,Hibernate才實現了Object/Relation       的映射。類似的,load和get方法也一樣會獲取Persistent狀態的對象。

    3、游離狀態:每次調用Session.close以后,所有跟這個session有關的處于
    Persistant的對象就變成了游離狀態。也許你要問Detached和Transient有什么區別。其實從我給的例子來說看不出什么區別,因為我這里ID是給定的,而真正開發的時候ID往往是自增的,那么Transient的對象是沒有ID    的,當save了以后就有了,顯而易見Detached的對象也是有ID,只不過這個對象已經和Hibernate脫離了關系。但是游離狀態的對象仍然和數據庫    中的記錄有一定聯系,至少游離狀態的對象知道數據庫中有條記錄的ID為xxx。從這一點上來講,游離狀態是可以自己創造出來的,只要你知道數據庫中的主鍵信息。
    在使用Hibernate開發的時候要分清楚這三種狀態,否則很容易出錯。比如不能去save一個游離狀態的對象,不能去update一個自由狀態的對象等等。

    五、結束語
    我要講的就這么多,這篇文章不是詳細介紹Hibernate,我只是總結了自己學習和使用Hibernate的一些感受和經驗,希望能給沒有用過Hibernate的開發者一個上手的指引。如果你看完了這篇文章仍然滿頭霧水,無從下手的話,我只能向你表示歉意,浪費你的時間了。不管怎樣,我強烈推薦一本書《深入淺出Hibernate》,這本書既能作為學習的教程,也能作為日后的查詢用書,相當實用。
    posted on 2007-05-31 10:46 注銷..... 閱讀(296) 評論(0)  編輯  收藏 所屬分類: 閱讀摘要
    主站蜘蛛池模板: 2020久久精品国产免费| 亚洲高清中文字幕综合网| 四虎国产精品免费久久| 两个人看的www高清免费视频| 亚洲高清一区二区三区电影| 亚洲精品国产成人| 亚洲啪啪综合AV一区| 免费永久在线观看黄网站| 中国在线观看免费高清完整版| 男女午夜24式免费视频| yellow免费网站| 男男黄GAY片免费网站WWW| 亚洲 欧洲 视频 伦小说| 亚洲的天堂av无码| 亚洲伦另类中文字幕| 精品亚洲永久免费精品| 亚洲欧洲日产国码一级毛片| 国产精品色午夜视频免费看| 在线观看日本免费a∨视频| 日本视频一区在线观看免费| 99视频免费播放| 久久精品国产这里是免费| 国产中文字幕在线免费观看| jizz18免费视频| g0g0人体全免费高清大胆视频| 最新亚洲人成无码网站| 国产亚洲综合精品一区二区三区| 亚洲色最新高清av网站| 亚洲jizzjizz在线播放久| 亚洲av乱码一区二区三区| 亚洲国产成AV人天堂无码| 亚洲精品自在线拍| 亚洲天堂中文字幕在线观看| 亚洲黄色片在线观看| 亚洲综合色丁香麻豆| 91久久亚洲国产成人精品性色 | 久久精品国产亚洲AV大全| 亚洲视频免费观看| 亚洲妓女综合网99| 亚洲人成人网站18禁| 边摸边吃奶边做爽免费视频99|