重新探索自我

              客觀條件受制于人,并不足懼。重要的是,我們擁有選擇的自由,可以對現實環境積極回應,
              為生命負責,為自己創造有利的機會,做一個“真正”操之在我的人!

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            3 隨筆 :: 10 文章 :: 5 評論 :: 0 Trackbacks

          一、Hibernate 的 CRUD 基本操作


          // 取得 session ,通常我們利用 hibernate.cfg.xml 的配置

          // 以用戶表和部門為例

          Configuration config = new Configuration().configure();

          SessionFactory sessionFactory =

          config.buildSessionFactory();

          Session session = sessionFactory.openSession();

          (1) 查詢數據

          // 取所有記錄

          Criteria criteria = session.createCriteria(User.class);

          Query query = session. createQuery ;

          List resultList = criteria.list()/ query . list();

          // 按條件查詢

          Query query = session .createQuery("from User where id between :ID1 and :ID2");

          query.setInteger("ID1",0);

          query.setInteger("ID2",2);

          Criteria criteria = getSession().createCriteria(User.class);

          criteria.add(Restrictions.eq("id",new Integer(1)));

          // 更復查的查詢見 Criteria 詳解

          (2) 插入記錄

          // 不設關聯的時候,可以直接 save 一個對象

          User user = new User();

          user.setUserName(“jiangliwen”);

          user.setSex(“ 男 ”);

          session.save(user);

          (3) 刪除記錄

          // 把一個 POJO 變成 PO 后就可以刪除,不過有時候方法會在刪除的時候自動變為 PO

          // 當你發現 User user = new User(New Integer(1)), 出錯的時候,說明不行

          User user = (User)session.load(User.class,new Integer(1));

          session.delete(user);

          (4) 更新記錄

          // 過程為取出、修改、保存

          User user = (User)session.load(User.class,new Integer(1));

          user.setRealName(“ 哈哈 ”);

          session.update(user);

          二、Criteria 查詢總結,能完成一般查詢、統計、分組、多表查詢


          填入任一查詢參數,模糊查詢

          Criteria criteria = getSession().createCriteria(User.class);
          criteria.add(Restrictions.eq("id",new Integer(1)));
          List list = criteria.list();
          criteria.add(Restrictions. like("username",”%jiang%”));

          您可以使用 Criteria 進行查詢,並使用 Order 對結果進行排序,例如使用 Oder.asc() 由小到大排序
          (反之則使用 desc() ):

          Criteria criteria = session.createCriteria(User.class);
          criteria.addOrder(Order.asc("age"));
          List users = criteria.list();


          setMaxResults() 方法可以限定查詢回來的筆數,如果配合 setFirstResult() 設定傳回查詢結果
          第一筆資料的位置,就可以實現簡單 的分頁,例如傳回第 51 筆之後的 50 筆資料(如果有的話):

          Criteria criteria = session.createCriteria(User.class);
          criteria.setFirstResult(51);
          criteria.setMaxResult(50);
          List users = criteria.list();


          您可以對查詢結果進行統計動作,使用 Projections 的 avg() 、 rowCount() 、 count() 、 max() 、 min() 、
          countDistinct() 等方法,例如對查詢結果的 "age" 作平均:

          Criteria criteria = session.createCriteria(User.class);
          criteria.setProjection(Projections.avg("age"));
          List users = criteria.list();
          Iterator iterator = users.iterator();
          while(iterator.hasNext()) {
          System.out.println(iterator.next());
          }


          還可以配合 Projections 的 groupProperty() 來對結果進行分組,例如以 "age" 進行分組,也就是如果資料中 "age"
          如果有 20 、 20 、 25 、 30 ,則以下會顯示 20 、 25 、 30 :

          Criteria criteria = session.createCriteria(User.class);
          criteria.setProjection(Projections.groupProperty("age"));
          List users = criteria.list();
          Iterator iterator = users.iterator();
          while(iterator.hasNext()) {
          System.out.println(iterator.next());
          }


          如果想結合統計與分組功能,則可以使用 ProjectionList ,例如下面的程式會計算每個年齡各有多少個人:

          ProjectionList projectionList = Projections.projectionList();
          projectionList.add(Projections.groupProperty("age"));
          projectionList.add(Projections.rowCount());

          Criteria criteria = session.createCriteria(User.class);
          criteria.setProjection(projectionList);
          List users = criteria.list();
          Iterator iterator = users.iterator();
          while(iterator.hasNext()) {
          Object[] o = (Object[]) iterator.next();
          System.out.println(o[0] + "\t" + o[1]);
          }


          如果有一個已知的物件,則可以根據這個物件作為查詢的依據,看看是否有屬性與之類似的物件,例如:

          User user = new User();
          user.setAge(new Integer(30));

          Criteria criteria = session.createCriteria(User.class);
          criteria.add(Example.create(user));

          List users = criteria.list();
          Iterator iterator = users.iterator();
          System.out.println("id \t name/age");
          while(iterator.hasNext()) {
          User ur = (User) iterator.next();
          System.out.println(ur.getId() +
          " \t " + ur.getName() +
          "/" + ur.getAge());
          }


          在這個例子中, user 物件中有已知的屬性 "age" 為 30 ,使用 Example 會自動過濾掉 user 的空屬性,
          並以之作為查詢的依據,也就是找出 "age" 同為 30 的資料。

          Criteria 可以進行複合查詢,即在原有的查詢基礎上再進行查詢,例如在 Room 對 User 的一對多關聯中,
          在查詢出所有的 Room 資料之後,希望再查詢 users 中 "age" 為 30 的 user 資料:

          Criteria roomCriteria = session.createCriteria(Room.class);
          Criteria userCriteria = roomCriteria.createCriteria("users");
          userCriteria.add(Restrictions.eq("age", new Integer(30)));
          List rooms = roomCriteria.list(); //
          只列出 users 屬性中有 user "age" 30 Room
          Iterator iterator = rooms.iterator();

          三、Hibernate 的事務管理

          Hibernate 是 JDBC 的輕量級封裝,本身并不具備事務管理能力。在事務管理層,

          Hibernate 將其委托給底層的 JDBC 或者 JTA ,以實現事務管理和調度功能。

          Hibernate 的默認事務處理機制基于 JDBC Transaction 。我們也可以通過配置文

          件設定采用 JTA 作為事務管理實現:

          < property name = "hibernate.transaction.factory_class" >

          net.sf.hibernate.transaction.JTATransactionFactory

          <!--net.sf.hibernate.transaction.JDBCTransactionFactory-->

          </ property >

          基于 JDBC 的事務管理

          session = sessionFactory.openSession();

          Transaction tx = session.beginTransaction();

          ……

          tx.commit();

          從 JDBC 層面而言,上面的代碼實際上對應著:

          Connection dbconn = getConnection();

          dbconn.setAutoCommit( false );

          ……

          dbconn.commit();

          基于 JTA 的事務管理

          JTA 提供了跨 Session 的事務管理能力。這一點是與 JDBC Transaction 最大的

          差異。

          JDBC 事務由 Connnection 管理,也就是說,事務管理實際上是在 JDBC Connection

          中實現。事務周期限于 Connection 的生命周期之類。同樣,對于基于 JDBC Transaction

          的 Hibernate 事務管理機制而言,事務管理在 Session 所依托的 JDBC Connection

          中實現,事務周期限于 Session 的生命周期。

          JTA 事務管理則由 JTA 容器實現, JTA 容器對當前加入事務的眾多 Connection 進

          行調度,實現其事務性要求。 JTA 的事務周期可橫跨多個 JDBC Connection 生命周期。

          同樣對于基于 JTA 事務的 Hibernate 而言, JTA 事務橫跨可橫跨多個 Session 。

          因此當 open 多個 session 時候,用 JTA 來管理事務。

          在 EJB 中使用 JTA Transaction 無疑最為簡便,我們只需要將 save 方法配置為

          JTA 事務支持即可,無需顯式申明任何事務,下面是一個 Session Bean 的 save 方法,

          它的事務屬性被申明為“ Required ”, EJB 容器將自動維護此方法執行過程中的事務:

          Hibernate 支持兩種鎖機制:即通常所說的“悲觀鎖( Pessimistic Locking )”

          和“樂觀鎖( Optimistic Locking )”

          悲觀鎖:保守態度,一旦上鎖,外界無法修改,直到釋放

          樂觀鎖: Hibernate 在其數據訪問引擎中內置了樂觀鎖實現。如果不用考慮外部系統對數

          據庫的更新操作,利用 Hibernate 提供的透明化樂觀鎖實現,將大大提升我們的

          生產力。

          < class

          name = "org.hibernate.sample.TUser"

          table = "t_user"

          dynamic-update = "true"

          dynamic-insert = "true"

          optimistic-lock = "version"

          >

          樂觀鎖,大多是基于數據版本

          ( Version )記錄機制實現。

          Cache 管理

          使用 cache 的目的往往是為了提高系統的性能;

          引入 Cache 機制的難點是如何保證內存中數據的有效性,否則臟數據的出現將給系統

          帶來難以預知的嚴重后果。

          Hibernate 中的 Cache 大致分為兩層,第一層 Cache 在 Session 實現,屬于事務

          級數據緩沖,一旦事務結束,這個 Cache 也就失效。

          第二層 Cache ,是 Hibernate 中對其實例范圍內的數據進行緩存的管理容器。

          我們需要討論的是第二層 Cache, 最簡單是基于 HashTable 的 cache 機制 .

          使用了 Cache 機制之后,應當注意編碼的結合,特別在查詢數據的時候使用:

          Query.list(); 取出所有的數據 , 一次 sql

          Query.iterate(); 兩次 sql, 一次去 ID , 如果有 cache 則優先查找,二次才取數據

          Session 管理

          SessionFactory 負責創建 Session , SessionFactory 是線程

          安全的,多個并發線程可以同時訪問一個 SessionFactory 并從中獲取 Session 實例。而

          Session 并非線程安全,也就是說,如果多個線程同時使用一個 Session 實例進行數據存取,

          則將會導致 Session 數據存取邏輯混亂。

          我們可以通過應用 ThreadLocal 機制 , 來維持一個 session

          public class HibernateUtil {

          private static SessionFactory sessionFactory;

          static {

          try {

          // Create the SessionFactory

          sessionFactory = new

          Configuration().configure().buildSessionFactory();

          } catch (HibernateException ex) {

          throw new RuntimeException(

          "Configuration problem: " + ex.getMessage(),

          ex

          );

          }

          }

          public static final ThreadLocal session = new ThreadLocal();

          public static Session currentSession() throws HibernateException

          {

          Session s = (Session) session.get();

          // Open a new Session, if this Thread has none yet

          if (s == null ) {

          s = sessionFactory.openSession();

          session.set(s);

          }

          return s;

          }

          public static void closeSession() throws HibernateException {

          Session s = (Session) session.get();

          session.set( null );

          if (s != null )

          s.close();

          }

          }

          對于 web 程序而言

          我們可以借助 Servlet2.3 規范中新引入的 Filter 機制,輕松實現線程生命周期內的 Session 管理

          四、再度思考

          1 、對 ORM 的理解

          ORM ( Object Relational Mapping )簡單的說,就是對象與關系的映射,對于實際應用來講,
          對象一般指面向對象中的對象,關系指關系型數據庫,對于我們具體的項目來說,就是將 java 中的
          對象與關系型數據庫( oracle , mysql )中的表聯系起來。

          ORM 解決方案有以下四部分組成:

          ■ 在持續類的對象上執行基本的 CRUD 操作的一組 API 。

          ■ 用于指定查詢的一種語言或一組 API ,這些查詢會引用類和類屬性。

          ■ 用于指定映射元數據的工具。

          ■ 實現 ORM 的一項技術,用來與事務對象交互以完成臟檢查、懶關聯存取和其它優化功能。

          ORM 這種解決方案的好處:

          對底層的封裝,因此,可移植性好,廠商獨立;

          解決對象 - 關系不匹配問題;

          在傳統我們在持久層通常使用 SQL 和 JDBC ,通常認為這樣方式已經讓大家感到厭倦了,特別是煩瑣的代碼;

          2 、 hibernate 可以認為是最優秀的 ORM 工具

          Hibernate 是一個雄心勃勃的項目,它的目標是成為 Java 中管理持續性數據問題的一種完

          整的解決方案。它協調應用與關系數據庫的交互,讓開發者解放出來專注于手中的業務問題。

          Hibernate 符合 java 編程習慣,它把數據庫與一個 POJO (簡單 Java 對象)關聯起來,
          使得對數據庫進行 CRUD 等操作時候,直接操作 Java 對象就可以了。通過以前 Java Bean 一樣 ,
          使用 setter 和 getter 方法。

          五、輔助工具

          (1)自動生成 hibernate 的映射文件

          一般考慮兩個方向:從數據庫到映射文件,從 java 類到映射文件

          數據庫到映射文件可以采用 Middlegen-Hibernate ,這個能很直觀的看到表之間的關系,并且能適當的做修改;

          從 java 類到映射文件的生成,可以用 XDoclet ,不過需要在 java 類中加上一些標記

          從生成的映射文件自動生成 java 類,可以用用一些工具,如 hbm2java

          從這四種自動生成工具來看,  mapping file, java file and DDL ,只要知道任何一種文件,都可以得到另外兩種文件,

          如:

          1.  只有 mapping file:

          mapping file---hbm2java----java---SchemaExport----DDL

          2. 只有 DDL

          DDL---Middlegen---hbm----hbm2java----java

          3. 只有 Java

          java---XDoclet---hbm----SchemaExport----DDL

          從這里,大家也可以體會到 , Hibernate 強大的靈活性

          不過我們通常習慣專門的工具設計數據庫,譬如 power designer 等工具,會自動生成 DDL ,
          所以我們更需要通過 DDL ,就自動生成 Mapping file 和 java 類

          (2)在 Eclipse 開發工具中,有一個比較好用的插件

          Hibernate Synchronizer

          ?  自動生成基本的 Hibernate 配置文件

          ?  自動由表結構生成 POJO 類, XML Mapping 和基本的 DAO 類。

          ?  精巧的繼承結構將自動生成代碼和用戶定制的代碼巧妙的分割開來。

          ?  將自動生成的代碼放在基類( Base* )中,將用戶定制的代碼放在子類中。分割了自動生成的代碼和用戶定制的代碼。

          ?  當表結構發生了變化時,插件只需要更改自己生成的基類,不用管用戶定制的子類。用戶定制的子類幾乎不用改動,
             或只需要很少的改動即可適應新的表結構。

          另:在 hibernate 使用一個 sessionFactory 操作多個數據庫時候,可以使用

          public StatelessSession openStatelessSession(Connection connection); 方法

          --------------------------------------------------------------------------------------

          路漫漫兮其修遠兮,吾將上下而求索!

          不過對于hibernate的學習暫且告一段落,哈哈!

          posted on 2006-01-18 10:42 蔣利文 閱讀(4873) 評論(3)  編輯  收藏 所屬分類: 技術總結

          評論

          # re: Hibernate學習總結 2006-01-18 12:33 蔣利文
          哈哈,自己先頂  回復  更多評論
            

          # re: Hibernate學習總結 2006-12-22 14:12 lfh
          有收獲,謝謝  回復  更多評論
            

          # RE: Hibernate學習總結 2009-03-29 00:17 瞿孟林
          理解深刻獨到  回復  更多評論
            

          主站蜘蛛池模板: 西乌珠穆沁旗| 平陆县| 蓬莱市| 綦江县| 资兴市| 永年县| 江油市| 齐齐哈尔市| 错那县| 东乌珠穆沁旗| 洛浦县| 浮山县| 弋阳县| 西峡县| 伊川县| 威远县| 梓潼县| 加查县| 昌都县| 宜阳县| 密山市| 运城市| 凤庆县| 郴州市| 通州区| 潞城市| 鲁甸县| 开原市| 扎兰屯市| 青海省| 安溪县| 玉溪市| 隆林| 高青县| 灵寿县| 醴陵市| 连山| 阜南县| 萨嘎县| 西和县| 武定县|