1. 程式人生 > >在JavaEE中使用Hibernate框架

在JavaEE中使用Hibernate框架

ejb con this 安裝 修飾 drive 主機 數據庫連接池 javaee

我們必須要了解一些Hibernate基礎對象,如下:

配置對象

配置對象是你在任何 Hibernate 應用程序中創造的第一個 Hibernate 對象,並且經常只在應用程序初始化期間創造。它代表了 Hibernate 所需一個配置或屬性文件。配置對象提供了兩種基礎組件。

  • 數據庫連接:由 Hibernate 支持的一個或多個配置文件處理。這些文件是 hibernate.propertieshibernate.cfg.xml

  • 類映射設置:這個組件創造了 Java 類和數據庫表格之間的聯系。

SessionFactory 對象

配置對象被用於創造一個 SessionFactory 對象,使用提供的配置文件為應用程序依次配置 Hibernate,並允許實例化一個會話對象。SessionFactory 是一個線程安全對象並由應用程序所有的線程所使用。

SessionFactory 是一個重量級對象所以通常它都是在應用程序啟動時創造然後留存為以後使用。每個數據庫需要一個 SessionFactory 對象使用一個單獨的配置文件。所以如果你使用多種數據庫那麽你要創造多種 SessionFactory 對象。

Session 對象

一個會話被用於與數據庫的物理連接。Session 對象是輕量級的,並被設計為每次實例化都需要與數據庫的交互。持久對象通過 Session 對象保存和檢索。Session 對象不應該長時間保持開啟狀態因為它們通常情況下並非線程安全,並且它們應該按照所需創造和銷毀。

Transaction 對象

一個事務代表了與數據庫工作的一個單元並且大部分 RDBMS 支持事務功能。在 Hibernate 中事務由底層事務管理器和事務(來自 JDBC 或者 JTA)處理。

這是一個選擇性對象,Hibernate 應用程序可能不選擇使用這個接口,而是在自己應用程序代碼中管理事務。

Query 對象

Query 對象使用 SQL 或者 Hibernate 查詢語言(HQL)字符串在數據庫中來檢索數據並創造對象。一個查詢的實例被用於連結查詢參數,限制由查詢返回的結果數量,並最終執行查詢。

Criteria 對象

Criteria 對象被用於創造和執行面向規則查詢的對象來檢索對象。

調用一個java方法需要正確的傳遞方法參數,那麽使用框架就是引用別人封裝好的jar包,按照別人規定好的方式進行配置並調用jar包裏的各種方法。只要是合格的Java程序員都會引用jar包,只是不知道Hibernate官方提供的jar包哪些是必須引用的,哪些是擴展的。Hibernate官方提供了對jar包的說明,這裏不再贅述。關鍵是怎樣寫好官方規定的配置文件,這是使用框架的重點

下面展示怎樣使用Hibernate框架,關鍵是配置文件

(重點一:)Hibernate 需要事先知道在哪裏找到映射信息,這些映射信息定義了 Java 類怎樣關聯到數據庫表。(重點二:)Hibernate 也需要一套相關數據庫和其它相關參數的配置設置。所有這些信息通常是作為一個標準的 Java 屬性文件提供的,名叫 hibernate.properties。又或者是作為 XML 文件提供的,名叫 hibernate.cfg.xml

我們將考慮 hibernate.cfg.xml 這個 XML 格式文件,來決定在我的例子裏指定需要的 Hibernate 應用屬性。這個 XML 文件中大多數的屬性是不需要修改的。這個文件保存在應用程序的類路徑的根目錄裏。

技術分享圖片

下面逐個貼出項目中各個文件的內容供大家參考

普通的pojo,沒啥好說的

技術分享圖片
public class Employee {
       private int id;
       private String firstName; 
       private String lastName;   
       private int salary;  

       public Employee() {}
       public Employee(int id,String fname, String lname, int salary) {
          this.id = id;
          this.firstName = fname;
          this.lastName = lname;
          this.salary = salary;
       }
       public int getId() {
          return id;
       }
       //省略getter、setter方法
}
Employee類

(重點一:)數據庫表和對象之間的映射關系

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD//EN"
 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 

<hibernate-mapping>
   <class name="com.wenji.entity.Employee" table="HTCPP.EMPLOYEE">
      <meta attribute="class-description">
         This class contains the employee detail. 
      </meta>
      <id name="id" type="int" column="id">
      </id>
      <property name="firstName" column="first_name" type="string"/>
      <property name="lastName" column="last_name" type="string"/>
      <property name="salary" column="salary" type="int"/>
   </class>
</hibernate-mapping>

映射文件

一個對象/關系型映射一般定義在 XML 文件中。映射文件指示 Hibernate 如何將已經定義的類或類組與數據庫中的表對應起來。

盡管有些 Hibernate 用戶選擇手寫 XML 文件,但是有很多工具可以用來給先進的 Hibernate 用戶生成映射文件。這樣的工具包括 XDoclet, MiddlegenAndroMDA

讓我們來考慮我們之前定義的 POJO 類,它的對象將延續到下一部分定義的表中。

create table EMPLOYEE(

ID INTEGER not null,
FIRST_NAME VARCHAR2(10),
LAST_NAME VARCHAR2(10),
SALARY INTEGER

)

你需要以格式 <classname>.hbm.xml保存映射文件。我們保存映射文件在 Employee.hbm.xml 中。讓我們來詳細地看一下在映射文件中使用的一些標簽:

  • 映射文件是一個以 <hibernate-mapping> 為根元素的 XML 文件,裏面包含所有<class>標簽。
  • <class> 標簽是用來定義從一個 Java 類到數據庫表的特定映射。Java 的類名使用 name 屬性來表示,數據庫表明用 table 屬性來表示。
  • <meta> 標簽是一個可選元素,可以被用來修飾類。
  • <id> 標簽將類中獨一無二的 ID 屬性與數據庫表中的主鍵關聯起來。id 元素中的 name 屬性引用類的性質,column 屬性引用數據庫表的列。type 屬性保存 Hibernate 映射的類型,這個類型會將從 Java 轉換成 SQL 數據類型。
  • 在 id 元素中的 <generator> 標簽用來自動生成主鍵值。設置 generator 標簽中的 class 屬性可以設置 native 使 Hibernate 可以使用 identity, sequencehilo 算法根據底層數據庫的情況來創建主鍵。
  • <property> 標簽用來將 Java 類的屬性與數據庫表的列匹配。標簽中 name 屬性引用的是類的性質,column 屬性引用的是數據庫表的列。type 屬性保存 Hibernate 映射的類型,這個類型會將從 Java 轉換成 SQL 數據類型。

還有一些其它屬性和元素可用在映射文件中。

(重點二:)數據庫各項參數配置

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM 
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
   <session-factory>
   <property name="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</property>
   <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>

   <!-- Assume test is the database name -->
   <property name="hibernate.connection.url"> jdbc:oracle:thin:@localhost:1521:orcl</property>
   <property name="hibernate.connection.username">system</property>
   <property name="connection.password">123456</property>
   <property name="show_sql">true</property> 

   <!-- List of XML mapping files -->
   <mapping resource="com/wenji/mapping/Employee.hbm.xml"/>

</session-factory>
</hibernate-configuration> 

hibernate.dialect:這個屬性使 Hibernate 應用為被選擇的數據庫生成適當的 SQL。
hibernate.connection.driver_class:JDBC 驅動程序類。
hibernate.connection.url:數據庫實例的 JDBC URL。
hibernate.connection.username:數據庫用戶名。
hibernate.connection.password:數據庫密碼。
hibernate.connection.pool_size:限制在 Hibernate 應用數據庫連接池中連接的數量。
hibernate.connection.autocommit:允許在 JDBC 連接中使用自動提交模式。

調用jar包封裝的方法

技術分享圖片
package com.wenji.test;

import java.util.List; 
import java.util.Date;
import java.util.Iterator; 

import org.hibernate.HibernateException; 
import org.hibernate.Session; 
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import com.wenji.entity.Employee;

public class ManageEmployee {
    private static SessionFactory factory; 
       public static void main(String[] args) {
          try{
             // 調用Configuration類的buildSessionFactory()方法:
             factory = new Configuration().configure().buildSessionFactory();
          }catch (Throwable ex) { 
             System.err.println("Failed to create sessionFactory object." + ex);
             throw new ExceptionInInitializerError(ex); 
          }
          ManageEmployee ME = new ManageEmployee();

          /* Add few employee records in database */
//          Integer empID1 = ME.addEmployee(1,"Zara", "Ali", 1000);
//          Integer empID2 = ME.addEmployee(2,"Daisy", "Das", 5000);
//          Integer empID3 = ME.addEmployee(3,"John", "Paul", 10000);

          /* List down all the employees */
          ME.listEmployees();

          /* Update employee‘s records */
//          ME.updateEmployee(empID1, 5000);

          /* Delete an employee from the database */
//          ME.deleteEmployee(empID2);

          /* List down new list of the employees */
//          ME.listEmployees();
       }
       /* Method to CREATE an employee in the database */
       public Integer addEmployee(int id,String fname, String lname, int salary){
          Session session = factory.openSession();
          Transaction tx = null;
          Integer employeeID = null;
          try{
             tx = session.beginTransaction();
             Employee employee = new Employee(id,fname, lname, salary);
             employeeID = (Integer) session.save(employee); 
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
          return employeeID;
       }
       /* Method to  READ all the employees */
       public void listEmployees( ){
          Session session = factory.openSession();
          Transaction tx = null;
          try{
             tx = session.beginTransaction();
             List employees = session.createQuery("FROM Employee").list(); 
             for (Iterator iterator = 
                               employees.iterator(); iterator.hasNext();){
                Employee employee = (Employee) iterator.next(); 
                System.out.print("First Name: " + employee.getFirstName()); 
                System.out.print("  Last Name: " + employee.getLastName()); 
                System.out.println("  Salary: " + employee.getSalary()); 
             }
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
       }
       /* Method to UPDATE salary for an employee */
       public void updateEmployee(Integer EmployeeID, int salary ){
          Session session = factory.openSession();
          Transaction tx = null;
          try{
             tx = session.beginTransaction();
             Employee employee = 
                        (Employee)session.get(Employee.class, EmployeeID); 
             employee.setSalary( salary );
             session.update(employee); 
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
       }
       /* Method to DELETE an employee from the records */
       public void deleteEmployee(Integer EmployeeID){
          Session session = factory.openSession();
          Transaction tx = null;
          try{
             tx = session.beginTransaction();
             Employee employee = 
                       (Employee)session.get(Employee.class, EmployeeID); 
             session.delete(employee); 
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
       }
}
測試方法

會話

Session 用於獲取與數據庫的物理連接。 Session 對象是輕量級的,並且設計為在每次需要與數據庫進行交互時被實例化。持久態對象被保存,並通過 Session 對象檢索找回。

該 Session 對象不應該長時間保持開放狀態,因為它們通常不能保證線程安全,而應該根據需求被創建和銷毀。Session 的主要功能是為映射實體類的實例提供創建,讀取和刪除操作。這些實例可能在給定時間點時存在於以下三種狀態之一:

  • 瞬時狀態: 一種新的持久性實例,被 Hibernate 認為是瞬時的,它不與 Session 相關聯,在數據庫中沒有與之關聯的記錄且無標識符值。
  • 持久狀態:可以將一個瞬時狀態實例通過與一個 Session 關聯的方式將其轉化為持久狀態實例。持久狀態實例在數據庫中沒有與之關聯的記錄,有標識符值,並與一個 Session 關聯。
  • 脫管狀態:一旦關閉 Hibernate Session,持久狀態實例將會成為脫管狀態實例。

若 Session 實例的持久態類別是序列化的,則該 Session 實例是序列化的。一個典型的事務應該使用以下語法:

Session session = factory.openSession();
Transaction tx = null;
try {
   tx = session.beginTransaction();
   // do some work
   ...
   tx.commit();
}
catch (Exception e) {
   if (tx!=null) tx.rollback();
   e.printStackTrace(); 
}finally {
   session.close();
}

如果 Session 引發異常,則事務必須被回滾,該 session 必須被丟棄。

Session 接口提供了很多方法,但在示例中僅展示幾個重要方法。可以查看 Hibernate 文件,查詢與 SessionSessionFactory 相關的完整方法目錄

到現在為止,你已經看到 Hibernate 如何使用 XML 映射文件來完成從 POJO 到數據庫表的數據轉換的,反之亦然。Hibernate 註釋是無需使用 XML 文件來定義映射的最新方法。你可以額外使用註釋或直接代替 XML 映射元數據。

Hibernate 註釋是一種強大的來給對象和關系映射表提供元數據的方法。所有的元數據被添加到 POJO java 文件代碼中,這有利於用戶在開發時更好的理解表的結構和 POJO。

如果你想讓你的應用程序移植到其它 EJB 3 的 ORM 應用程序中,您必須使用註釋來表示映射信息,但是如果想要得到更大的靈活性,那麽你應該使用基於 XML 的映射。

Hibernate 註釋的環境設置

首先你必須確定你使用的是 JDK 5.0,否則你需要升級你的 JDK 至 JDK 5.0,來使你的主機能夠支持註釋。

其次,你需要安裝 Hibernate 註釋包,可以從 sourceforge 行下載:(下載 Hibernate 註釋) 並且從 Hibernate 註釋發布中拷貝 hibernate-annotations.jar, lib/hibernate-comons-annotations.jarlib/ejb3-persistence.jar 到你的 CLASSPATH。

項目結構如下,和之前的項目結構相比,少了Employee.hbm.xml,這個xml文件是用來描述數據庫表與java對象的映射關系的,那麽這個文件被誰替代了呢?

技術分享圖片

下面逐個貼出項目中各個文件的內容供大家參考

package com.wenji.entity;

import javax.persistence.*;

@Entity
@Table(name = "htcpp.EMPLOYEE")
public class Employee {
       @Id
       @Column(name = "id")
       private int id;

       @Column(name = "first_name")
       private String firstName;

       @Column(name = "last_name")
       private String lastName;

       @Column(name = "salary")
       private int salary;  


       public Employee() {}
       public Employee(int id,String fname, String lname, int salary) {
          this.id = id;
          this.firstName = fname;
          this.lastName = lname;
          this.salary = salary;
       }
       //省略getter、setter方法
}

@Entity 註釋

EJB 3 標準的註釋包含在 javax.persistence 包,所以我們第一步需要導入這個包。第二步我們對 Employee 類使用 @Entity 註釋,標誌著這個類為一個實體 bean,所以它必須含有一個沒有參數的構造函數並且在可保護範圍是可見的。

@Table 註釋

@table 註釋允許您明確表的詳細信息保證實體在數據庫中持續存在。

@table 註釋提供了四個屬性,允許您覆蓋的表的名稱,目錄及其模式,在表中可以對列制定獨特的約束。現在我們使用的是表名為 EMPLOYEE。

@Id 和 @GeneratedValue 註釋

每一個實體 bean 都有一個主鍵,你在類中可以用 @Id 來進行註釋。主鍵可以是一個字段或者是多個字段的組合,這取決於你的表的結構。

默認情況下,@Id 註釋將自動確定最合適的主鍵生成策略,但是你可以通過使用 @GeneratedValue 註釋來覆蓋掉它。strategygenerator 這兩個參數我不打算在這裏討論,所以我們只使用默認鍵生成策略。讓 Hibernate 確定使用哪些生成器類型來使代碼移植於不同的數據庫之間。

@Column Annotation

@Column 註釋用於指定某一列與某一個字段或是屬性映射的細節信息。您可以使用下列註釋的最常用的屬性:

  • name 屬性允許顯式地指定列的名稱。

  • length 屬性為用於映射一個值,特別為一個字符串值的列的大小。

  • nullable 屬性允許當生成模式時,一個列可以被標記為非空。

  • unique 屬性允許列中只能含有唯一的內容

hibernate.cfg.xml文件和之前相比,註釋掉了映射文件的信息

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM 
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
   <session-factory>
   <property name="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</property>
   <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>

   <!-- Assume test is the database name -->
   <property name="hibernate.connection.url"> jdbc:oracle:thin:@localhost:1521:orcl</property>
   <property name="hibernate.connection.username">system</property>
   <property name="connection.password">123456</property>
   <property name="show_sql">true</property> 

   <!-- List of XML mapping files -->
   <!--    <mapping resource="com/wenji/mapping/Employee.hbm.xml"/> -->

</session-factory>
</hibernate-configuration> 

和之前的示例方法相比,只有創建factory的方式變了,其他的都一樣

技術分享圖片
package com.wenji.test;

import java.util.List; 
import java.util.Date;
import java.util.Iterator; 

import org.hibernate.HibernateException; 
import org.hibernate.Session; 
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import com.wenji.entity.Employee;

public class ManageEmployee {
   private static SessionFactory factory; 
   public static void main(String[] args) {
      try{
         factory = new AnnotationConfiguration().
                   configure().
                   //addPackage("com.xyz") //add package if used.
                   addAnnotatedClass(Employee.class).
                   buildSessionFactory();
      }catch (Throwable ex) { 
         System.err.println("Failed to create sessionFactory object." + ex);
         throw new ExceptionInInitializerError(ex); 
      }
      ManageEmployee ME = new ManageEmployee();

      /* Add few employee records in database */
//      Integer empID1 = ME.addEmployee("Zara", "Ali", 1000);
//      Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
//      Integer empID3 = ME.addEmployee("John", "Paul", 10000);

      /* List down all the employees */
      ME.listEmployees();

      /* Update employee‘s records */
//      ME.updateEmployee(empID1, 5000);

      /* Delete an employee from the database */
//      ME.deleteEmployee(empID2);

      /* List down new list of the employees */
//      ME.listEmployees();
   }
   /* Method to CREATE an employee in the database */
   public Integer addEmployee(String fname, String lname, int salary){
      Session session = factory.openSession();
      Transaction tx = null;
      Integer employeeID = null;
      try{
         tx = session.beginTransaction();
         Employee employee = new Employee();
         employee.setFirstName(fname);
         employee.setLastName(lname);
         employee.setSalary(salary);
         employeeID = (Integer) session.save(employee); 
         tx.commit();
      }catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      }finally {
         session.close(); 
      }
      return employeeID;
   }
   /* Method to  READ all the employees */
   public void listEmployees( ){
      Session session = factory.openSession();
      Transaction tx = null;
      try{
         tx = session.beginTransaction();
         List employees = session.createQuery("FROM Employee").list(); 
         for (Iterator iterator = 
                           employees.iterator(); iterator.hasNext();){
            Employee employee = (Employee) iterator.next(); 
            System.out.print("First Name: " + employee.getFirstName()); 
            System.out.print("  Last Name: " + employee.getLastName()); 
            System.out.println("  Salary: " + employee.getSalary()); 
         }
         tx.commit();
      }catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      }finally {
         session.close(); 
      }
   }
   /* Method to UPDATE salary for an employee */
   public void updateEmployee(Integer EmployeeID, int salary ){
      Session session = factory.openSession();
      Transaction tx = null;
      try{
         tx = session.beginTransaction();
         Employee employee = 
                    (Employee)session.get(Employee.class, EmployeeID); 
         employee.setSalary( salary );
         session.update(employee); 
         tx.commit();
      }catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      }finally {
         session.close(); 
      }
   }
   /* Method to DELETE an employee from the records */
   public void deleteEmployee(Integer EmployeeID){
      Session session = factory.openSession();
      Transaction tx = null;
      try{
         tx = session.beginTransaction();
         Employee employee = 
                   (Employee)session.get(Employee.class, EmployeeID); 
         session.delete(employee); 
         tx.commit();
      }catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      }finally {
         session.close(); 
      }
   }
}
測試方法

在JavaEE中使用Hibernate框架