--Hibernaet使-用-存-儲-過-程

 User.hbm.xml文件的內容如下:

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">



<hibernate-mapping package="com.amigo.proc.model">

    <class name="User" table="tbl_user">

        <id name="userid" column="userid">

            <generator class="assigned"/>

        </id>

        <property name="name" column="name" type="string" />

        <property name="blog" column="blog" type="string" />

    </class>

   

    <sql-query name="getUserList" callable="true">

        <return alias="user" class="User">

            <return-property name="userid" column="userid"/>

            <return-property name="name" column="name"/>

            <return-property name="blog" column="blog" />

        </return>

        {call getUserList()}

    </sql-query>

</hibernate-mapping>

在該文件中需注意<sql-query…></sql-query>中的這段代碼,調用的存儲過程在其中定義,並定義了調用存儲過程後將記錄組裝成User對象,同時對記錄的字段與對象的屬性進行相關映射。

 

public class ProcTest {



    /** *//**

     * @param args

     */

    public static void main(String[] args) throws Exception {

        ProcTest proc = new ProcTest();

        Session session = HibernateSessionFactory.getSession();

        proc.testProcQuery(session);

        proc.testProcUpdate(session);

        System.out.println("update successfully");

        

        proc.testProcInsert(session);

        System.out.println("insert successfully");

        

        proc.testProcDelete(session);

        System.out.println("delete successfully");

        session.close();

    }

   

    /** *//**

     * 測試實現查詢的存儲過程

     * @throws Exception

     */

    private void testProcQuery(Session session) throws Exception {

        //查詢用戶列表

        List list = session.getNamedQuery("getUserList").list();

        for (int i = 0; i < list.size(); i++) {

            User user = (User) list.get(i);   

            System.out.print("序號: " + (i+1));

            System.out.print(", userid: " + user.getUserid());

            System.out.print(", name: " + user.getName());

            System.out.println(", blog: " + user.getBlog());

        }

    }

   

    /** *//**

     * 測試實現更新的存儲過程

     * @throws Exception

     */

    private void testProcUpdate(Session session) throws Exception {

        //更新用戶信息

        Transaction tx = session.beginTransaction();

        Connection con = session.connection();

        String procedure = "{call updateUser(?, ?, ?)}";

        CallableStatement cstmt = con.prepareCall(procedure);

        cstmt.setString(1, "陳xx");

        cstmt.setString(2, "http://www.blogjava.net/sterningChen");

        cstmt.setString(3, "sterning");

        cstmt.executeUpdate();

        tx.commit();

    }



    /** *//**

     * 測試實現插入的存儲過程

     * @throws Exception

     */

    private void testProcInsert(Session session) throws Exception {

        //創建用戶信息

        session.beginTransaction();

        PreparedStatement st = session.connection().prepareStatement("{call createUser(?, ?, ?)}");

        st.setString(1, "amigo");

        st.setString(2, "阿蜜果");

        st.setString(3, "http://www.wblogjava.net/amigoxie");

        st.execute();

        session.getTransaction().commit();

    }

   

    /** *//**

     * 測試實現刪除的存儲過程

     * @throws Exception

     */

    private void testProcDelete(Session session) throws Exception {

        //刪除用戶信息

        session.beginTransaction();

        PreparedStatement st = session.connection().prepareStatement("{call deleteUser(?)}");

        st.setString(1, "amigo");

        st.execute();

        session.getTransaction().commit();

    }

}


   在本類中,調用查詢類存儲過程時,調用session.getNamedQuery("…")方法來獲得User.hbm.xml中配置的查詢存儲過程。在其餘的存儲過程調用的測試中,首先通過hibernate的session獲得connection,然後調用connection對象的相應方法來實現存儲過程的調用。

該類的執行結果如下:

Hibernate: {call getUserList()}

序號: 1, userid: ant, name: 螞蟻, blog: [url]http://www.blogjava.net/qixiangnj[/url]

序號: 2, userid: beansoft, name: bean, blog: [url]http://www.blogjava.net/beansoft[/url]

序號: 3, userid: sterning, name: 似水流年, blog: [url]http://www.blogjava.net/sterning[/url]

序號: 4, userid: tom, name: tom, blog: [url]http://www.blogjava.net/tom[/url]

update successfully

insert successfully

delete successfully

五.總結
   本例提出了在hibernate3中調用mysql的存儲過程的實現方案,從本例可以看出,hibernate提供了在*.hbm.xml中配置調用存儲過程,並通過向用戶提供session.getNamedQuery(“…”)方法來調用配置的調用查詢相關的存儲過程的方法,另外,hibernate還提供了取得sql的connection的方法,從而能夠通過connection中存儲過程調用相關的方法來實現存儲過程的調用。

DamYankee 2007-12-13 18:44

[url]http://java.ccidnet.com/art/3737/20030124/472461_1.html[/url]

DamYankee 2007-12-15 15:48

Hibernate 要點

1. 三W What, Why, When 什麼是, 爲什麼, 什麼時候
        what:是一個 OR Mappming(O Object 對象 R relative 關係數據庫 映射) 框架(framework)
        why:
        把一個對象的人 分解成一張橫的表的幾列
        Person => id, name, age
        根據對象自動生成對應的關係數據庫的 SQL, 可以簡化 Java 數據庫開發, 代替 JDBC 來實現持久化(Persistence).
        when:
        1) 必須有明確的對象設計的時候才能用 Hibernate.
        2) 數據庫是用大量的存儲過程實現的 不能用 Hibernate !!!
        3) 如果多表查詢, 也要慎重 Hibernate, 查詢順序不可預料(createSQLQuery(手寫查詢語句))
       
2. 怎麼用
        1) 全局配置信息被 Configuration 類解析(配置解析器)
         a) 怎麼連接數據庫
        hibernate.cfg.xml
        獲取數據庫連接的參數(URL, username, password)
        方言 (Dialect) 爲了對不同的數據庫生成相應的 SQL
         b) 有那些映射文件需要處理

Configuration 類
  Configuration類負責管理 Hibernate 的配置信息。Hibernate 運行時需要
獲取一些底層實現的基本信息,其中幾個關鍵屬性包括:
數據庫URL
數據庫用戶
數據庫用戶密碼
數據庫JDBC驅動類
數據庫dialect,用於對特定數據庫提供支持,其中包含了針對特定數據庫特性
的實現,如Hibernate數據類型到特定數據庫數據類型的映射等。
使用 Hibernate 必須首先提供這些基礎信息以完成初始化工作,爲後繼操作做好準
備。這些屬性在hibernate配置文件(hibernate.cfg.xml )中加以設 定.
調用:
Configuration config = new Configuration().configure();
  時,Hibernate會自動在當前的 CLASSPATH 中搜尋 hibernate.cfg.xml文件並將其讀
取到內存中作爲後繼操作的基礎配置。Configuration 類一般只有在獲取 SessionFactory
時需要涉及,當獲取 SessionFactory 之後,由於配置信息已經由 Hibernate 維護並綁定
在返回的SessionFactory之上,因此一般情況下無需再對其進行操作。

示例的配置文件:
         <?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<session-factory>
  <!-- 顯示後臺的 SQL, 便於調試 -->
  <property name="show_sql">true</property>
        <property name="connection.username">classiccars</property>
        <property name="connection.url">
                jdbc:derby://localhost:1527/myeclipse;create=true
        </property>
        <property name="dialect">org.hibernate.dialect.DerbyDialect</property>
        <property name="connection.driver_class">org.apache.derby.jdbc.ClientDriver</property>
        <property name="connection.password">myeclipse</property>
       
        <!-- 實體映射文件 -->
        <mapping resource="dao/User.hbm.xml" />

</session-factory>


        2) 實體類(POJO Plain and Old Java Ojbect) JavaBean 的要求
        值對象, 只有 getter, setter, 沒有業務方法
        什麼樣的對象需要映射
        public class User implements java.io.Serializable {
                private int id;
                private String username;
                getxxx
                setxxx
        }

                a) 要有主鍵字段.
                b) 可序列化(緩存, 有時候在內存, 有時候放硬盤)

        3) 實體映射文件 實體名.hbm.xml
        告訴 Hibernate 怎麼來做對象映射. 向哪個表插入數據, 每個屬性的數據類型, 以及對應數據表裏的列名.
        一個文件配置多個實體類也是可以的, 一般來說是一個實體一個配置文件.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="dao.User" table="users(數據庫表格)" catalog="數據庫名字">
   
    <!-- 主鍵字段配置, hibernate爲我們生成主鍵id, 必須定義-->
        <id name="id" type="java.lang.Integer">
            <column name="id" />
            <generator class="increment" />
            <!--  increment 是先從數據庫取最大ID然後加1, 再存入數據庫
            assigned 必須手工賦值給一個 ID
            auto, identify, sequence, native, uuid.hex, hilo 等等
            -->
        </id>
        
        <!-- property 默認把類的變量映射爲相同名字的表列,當然我們可以修改其映射方式-->
        
        <!-- 類型寫法兩種 Hibernate type: string, int; Java 類的全名:  java.lang.Integer -->
        <property name="username" type="java.lang.String">
                        <!-- 指定對應數據庫中的字段信息 -->
            <column name="username" length="200" not-null="true" />
        </property>
        <property name="password" type="java.lang.String">
            <column name="password" length="20" not-null="true" />
        </property>
        <property name="age" type="java.lang.Integer">
            <column name="age" />
        </property>
    </class>
</hibernate-mapping>

多對多幾乎沒人用, 一對一常用, 一對多比較常用.

3. SessionFactory 和 Session
        SessionFactory ==> 等價於 DriverManager, 只需要一個.
  SessionFactory 負責創建 Session 實例。可以通過 Configuation 實例構建
SessionFactory:

SessionFactory sessionFactory = config.buildSessionFactory();
  
  Configuration實例config會根據當前的配置信息,構造 SessionFactory實例並返回。
SessionFactory 一旦構造完畢,即被賦予特定的配置信息。也就是說,之後 config 的任
何變更將不會影響到已經創建的 SessionFactory 實例(sessionFactory)。如果需要
使用基於改動後的 config 實例的 SessionFactory,需要從 config 重新構建一個
SessionFactory實例。
  
Session  ==>  等價於 JDBC中的 Connection
  Session實例通過SessionFactory實例構建:
  Session session = sessionFactory.openSession();

完整示例代碼:

  // 0. 加載配置和驅動等, 生成 Session 工廠(相當於連接池或者 DriverManager)
  Configuration config = new Configuration().configure();
  SessionFactory sessionFactory = config.buildSessionFactory();
        // 1. 打開 session
        Session session = sessionFactory.openSession();
        // 2. 打開事務(Transaction)
        org.hibernate.Transaction tran = session.beginTransaction();
        // 3. 生成實體類
        User bean = new User();
        // 4. 給 bean 賦值
        bean.setUsername("zhangsan");
        // 5. 保存或者更新(並沒有立即保存到數據)
        session.save(bean);
        // 6. 提交事務(真正的保存或者更新數據)
        tran.commit();

        // 7. 做查詢, 首先創建查詢對象
        String queryString = "from User";// HSQL 操作的是實體, 不是數據庫表格
        Query query = getSession().createQuery(queryString);
        // 8. 讀取查詢結果
        java.util.List<User> result = query.list();

4. Transaction 事務
  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 進行處理無疑是最簡單的實現方式,Hibernate 對於 JDBC
事務的封裝也極爲簡單。
我們來看下面這段代碼:
      session = sessionFactory.openSession();
      Transaction tx = session.beginTransaction();
     ……
      tx.commit();
從JDBC層面而言,上面的代碼實際上對應着:
        Connection dbconn = getConnection();
      dbconn.setAutoCommit(false);
     ……
      dbconn.commit();
就是這麼簡單,Hibernate並沒有做更多的事情(實際上也沒法做更多的事情),只
是將這樣的JDBC代碼進行了封裝而已。

5. 查詢對象 Query(Hibernate 參考文檔的第11章) 和 HSQL
     普通查詢如上所示
     
      帶參數的查詢(相當於 PreparedStatement)
      
     q = session.createQuery("from User u where u.name= :name");
     q.setString("name", "張三");
     q = session.createQuery("from User u where u.name= ?");
     q.setString(0, "張三");
     
     Native SQL 方式(用於特定的數據庫的查詢)
     List cats=session.createSQLQuery(
"SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10",
"cat",
Cat.class
).list();
Listcat s=session.createSQLQuery(
"SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex},"+
"{cat}.MATE AS{cat.mate}, {cat}.SUBCLASSAS {cat.class},..."+
"FROM CAT {cat} WHERE ROWNUM<10",
"cat",
Cat.class
).list();
     
     過濾重複記錄:
     select distinct cat.name from Cat cat
6. 一對多, 多對一, 多對多中的懶惰加載 Lazy, Fetch
新版本的Hibernate在處理Session的時候已經內置了延遲加載機制,只有在真正發生數據庫操作的時候,纔會從數據庫連接池獲取數據庫連接. 這會帶來問題.
    例如一對多:
    <set
            name="addresses"
            table="t_address"
            lazy="false"
            inverse="false"
            cascade="all"
        >
...              <one-to-many
                  class="org.hibernate.sample.TAddress"
              />
        </set>
        示例代碼:
        Query q = getSession().createQuery("from User");
List userList = q.list();   
TUser user =(TUser)userList.get(0);
System.out.println("User name => "+user.getName());
Set hset = user.getAddresses();
session.close();//關閉Session   
TAddress addr = (TAddress)hset.toArray()[0];
System.out.println(addr.getAddress());
  
運行時拋出異常:
LazyInitializationException - Failed to lazily initialize a collection - no session or session was closed
如果我們稍做調整,將session.close放在代碼末尾,則不會發生這樣的問題。但是一般 DAO 執行結束後即關閉了 session.
這意味着,只有我們實際加載user關聯的address時,Hibernate才試圖通過
session從數據庫中加載實際的數據集,而由於我們讀取address之前已經關閉了
session,所以報出session已關閉的錯誤。
解決辦法:
1) Hibernate.initialize方法可以通過強制加載關聯對象實現這一功能:

  Hibernate.initialize(user.getAddresses());
  session.close();
  2) 用 HQL 裏面的 fetch
  from User fetch all properties

  3) lazy="false"
  
7. Hibernate 分頁
int currentPage = 0;// 當前頁
int pageSize = 10;// 顯示記錄數
String queryString = "from User";
Query queryObject = getSession().createQuery(queryString);
// 設置從哪裏讀
queryObject.setFirstResult((currentPage - 1) * pageSize);
// 設置一共讀幾行
queryObject.setMaxResults(pageSize);
return queryObject.list();

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章