1. 程式人生 > >JPA入門例子(採用JPA的hibernate實現版本) 及單元測試

JPA入門例子(採用JPA的hibernate實現版本) 及單元測試

原文地址:http://blog.csdn.net/hmk2011/article/details/6289151

(1)、JPA介紹:

      JPA全稱為Java Persistence API ,Java持久化API是Sun公司在Java EE 5規範中提出的Java持久化介面。JPA吸取了目前Java持久化技術的優點,旨在規範、簡化Java物件的持久化工作。使用JPA持久化物件,並不是依賴於某一個ORM框架。

     為什麼要使用JAP?
      在說為什麼要使用JPA之前,我們有必要了解為什麼要使用ORM技術。

ORM 是Object-Relation-Mapping,即物件關係影射技術,是物件持久化的核心。ORM是對JDBC的封裝,從而解決了JDBC的各種存在問題:

a) 繁瑣的程式碼問題

用JDBC的API程式設計訪問資料庫,程式碼量較大,特別是訪問欄位較多的表的時候,程式碼顯得繁瑣、累贅,容易出錯。例如:PreparedStatement pstmt=con.prepareStatment("insert into account value(?,?,?,?,?,?,?,?,?)");

ORM則建立了Java物件與資料庫物件之間的影射關係,程式設計師不需要編寫複雜的SQL語句,直接操作Java物件即可,從而大大降低了程式碼量,也使程式設計師更加專注於業務邏輯的實現。

b) 資料庫物件連線問題

關係資料物件之間,存在各種關係,包括1對1、1對多、多對1、多對多、級聯等。在資料庫物件更新的時候,採用JDBC程式設計,必須十分小心處理這些關係,以保證維持這些關係不會出現錯誤,而這個過程是一個很費時費力的過程。

ORM建立Java物件與資料庫物件關係影射的同時,也自動根據資料庫物件之間的關係建立Java物件的關係,並且提供了維持這些關係完整、有效的機制。

c) 系統架構問題

JDBC屬於資料訪問層,但是使用JDBC程式設計時,必須知道後臺是用什麼資料庫、有哪些表、各個表有有哪些欄位、各個欄位的型別是什麼、表與表之間什麼關係、建立了什麼索引等等與後臺資料庫相關的詳細資訊。

使用ORM技術,可以將資料庫層完全隱蔽,呈獻給程式設計師的只有Java的物件,程式設計師只需要根據業務邏輯的需要呼叫Java物件的Getter和 Setter方法,即可實現對後臺資料庫的操作,程式設計師不必知道後臺採用什麼資料庫、有哪些表、有什麼欄位、表與表之間有什麼關係。

d) 效能問題

採用JDBC程式設計,在很多時候存在效率低下的問題。

pstmt =conn.prepareStatement("insert into user_info values(?,?)");
       for (int i=0; i<1000; i++) {
          pstmt.setInt(1,i);
          pstmt.setString(2,"User"+i.toString());
          pstmt.executeUpdate();
       }

以上程式將向後臺數據庫傳送1000次SQL語句執行請求,執行效率較低。

採用ORM技術,ORM框架將根據具體資料庫操作需要,會自動延遲向後臺數據庫傳送SQL請求,ORM也可以根據實際情況,將資料庫訪問操作合成,儘量減少不必要的資料庫操作請求。

JPA是目前比較流行的一種ORM技術之一,所以他擁有ORM技術的各種特點,當然他還有自己的一些優勢:

1 標準化
  JPA 是 JCP 組織釋出的 Java EE 標準之一,因此任何聲稱符合 JPA 標準的框架都遵循同樣的架構,提供相同的訪問 API,這保證了基於JPA開發的企業應用能夠經過少量的修改就能夠在不同的JPA框架下執行。
2 對容器級特性的支援
  JPA 框架中支援大資料集、事務、併發等容器級事務,這使得 JPA 超越了簡單持久化框架的侷限,在企業應用發揮更大的作用。
3 簡單易用,整合方便
  JPA的主要目標之一就是提供更加簡單的程式設計模型:在JPA框架下建立實體和建立Java 類一樣簡單,沒有任何的約束和限制,只需要使用 javax.persistence.Entity進行註釋;JPA的框架和介面也都非常簡單,沒有太多特別的規則和設計模式的要求,開發者可以很容易的掌握。JPA基於非侵入式原則設計,因此可以很容易的和其它框架或者容器整合。
4 可媲美JDBC的查詢能力
  JPA的查詢語言是面向物件而非面向資料庫的,它以面向物件的自然語法構造查詢語句,可以看成是Hibernate HQL的等價物。JPA定義了獨特的JPQL(Java Persistence Query Language),JPQL是EJB QL的一種擴充套件,它是針對實體的一種查詢語言,操作物件是實體,而不是關係資料庫的表,而且能夠支援批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能夠提供的高階查詢特性,甚至還能夠支援子查詢。
5 支援面向物件的高階特性
  JPA 中能夠支援面向物件的高階特性,如類之間的繼承、多型和類之間的複雜關係,這樣的支援能夠讓開發者最大限度的使用面向物件的模型設計企業應用,而不需要自行處理這些特性在關係資料庫的持久化。

(2)、具體例子

    完成工程後工程結構如下圖:

   

 (注意:persistence.xml檔案的位置決定永續性的根(Persistence Root)。永續性的根為JAR檔案或者包含META-INF目錄(前提是persistence.xml位於此)的目錄。一般將這個persistence.xml檔案放在src下的META-INF中。命名及位置都不能變)

a)、匯入相關jar包(見上圖)和建立META-INF和persistence.xml檔案.

persistence.xml配置如下:(我用的資料為mysql,採用不同資料庫及JPA的不同實現版本會導致配置內容不同)

  1. <persistencexmlns="http://java.sun.com/xml/ns/persistence"
  2.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3.     xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_version=1">
  4.     <persistence-unitname="mysqlJPA"transaction-type="RESOURCE_LOCAL">
  5.         <properties>
  6.             <propertyname="hibernate.dialect"value="org.hibernate.dialect.MySQL5Dialect"/>
  7.             <propertyname="hibernate.connection.driver_class"value="com.mysql.jdbc.Driver"/>
  8.             <propertyname="hibernate.connection.username"value="root"/>
  9.             <propertyname="hibernate.connection.password"value="123456"/>
  10.             <propertyname="hibernate.connection.url"value="jdbc:mysql://localhost:3306/db1"/>
  11.             <propertyname="hibernate.max_fetch_depth"value="3"/>
  12.             <propertyname="hibernate.hbm2ddl.auto"value="update"/>
  13.         </properties>
  14.     </persistence-unit>
  15. </persistence>

b)、編寫實體bean,如下:

  1. package com.hmk.bean;  
  2. import javax.persistence.Column;  
  3. import javax.persistence.Entity;  
  4. import javax.persistence.GeneratedValue;  
  5. import javax.persistence.Id;  
  6. @Entity  
  7. publicclass Person {  
  8.     privateint id;  
  9.     private String name;  
  10.     @Id @GeneratedValue  
  11.     publicint getId() {  
  12.         return id;  
  13.     }  
  14.     publicvoid setId(int id) {  
  15.         this.id = id;  
  16.     }  
  17.     @Column(length=12)  
  18.     public String getName() {  
  19.         return name;  
  20.     }  
  21.     publicvoid setName(String name) {  
  22.         this.name = name;  
  23.     }  
  24. }  
   

c)、編寫junit測試程式碼,如下:

  1. package junit.test;  
  2. import javax.persistence.EntityManager;  
  3. import javax.persistence.EntityManagerFactory;  
  4. import javax.persistence.Persistence;  
  5. import org.junit.BeforeClass;  
  6. import org.junit.Test;  
  7. import com.hmk.bean.Person;  
  8. publicclass JpaTest {  
  9.     @BeforeClass
  10.     publicstaticvoid setUpBeforeClass() throws Exception {  
  11.     }  
  12.     @Testpublicvoid createTable(){  
  13.         //可以驗證生成表是否正確
  14.         EntityManagerFactory factory = Persistence.createEntityManagerFactory("mysqlJPA");  
  15.         factory.close();  
  16.     }  
  17.     @Testpublicvoid save(){  
  18.         EntityManagerFactory factory = Persistence.createEntityManagerFactory("mysqlJPA");  
  19.         EntityManager em = factory.createEntityManager();  
  20.         em.getTransaction().begin();  
  21.         Person person = new Person(); //person為new狀態
  22.         person.setName("zhang san");  
  23.         em.persist(person); //持久化實體
  24.         em.getTransaction().commit();  
  25.         em.close();  
  26.         factory.close();  
  27.     }  
  28.     //new 、託管、脫管、刪除
  29.     @Testpublicvoid update(){  
  30.         EntityManagerFactory factory = Persistence.createEntityManagerFactory("mysqlJPA");  
  31.         EntityManager em = factory.createEntityManager();  
  32.         em.getTransaction().begin();  
  33.         Person person = em.find(Person.class1);  
  34.         person.setName("hmk"); //person為託管狀態
  35.         em.getTransaction().commit();  
  36.         em.close();  
  37.         factory.close();  
  38.     }  
  39.     @Testpublicvoid update2(){  
  40.         EntityManagerFactory factory = Persistence.createEntityManagerFactory("mysqlJPA");  
  41.         EntityManager em = factory.createEntityManager();  
  42.         em.getTransaction().begin();  
  43.         Person person = em.find(Person.class1);  
  44.         em.clear(); //把實體管理器中的所有實體變為脫管狀態
  45.         person.setName("hmk2");  
  46.         em.merge(person); //把脫管狀態變為託管狀態,merge可以自動選擇insert or update 資料
  47.         em.getTransaction().commit();  
  48.         em.close();  
  49.         factory.close();  
  50.     }  
  51.     @Testpublicvoid remove(){  
  52.         EntityManagerFactory factory = Persistence.createEntityManagerFactory("mysqlJPA");  
  53.         EntityManager em = factory.createEntityManager();  
  54.         em.getTransaction().begin();  
  55.         Person person = em.find(Person.class1);  
  56.         em.remove(person); //刪除實體
  57.         em.getTransaction().commit();  
  58.         em.close();  
  59.         factory.close();  
  60.     }  
  61.     @Testpublicvoid find(){  
  62.         EntityManagerFactory factory = Persistence.createEntityManagerFactory("mysqlJPA");  
  63.         EntityManager em = factory.createEntityManager();  
  64.         Person person = em.find(Person.class2); //類似於hibernate的get方法,沒找到資料時,返回null
  65.         System.out.println(person.getName());  
  66.         em.close();  
  67.         factory.close();  
  68.     }  
  69.     @Testpublicvoid find2(){  
  70.         EntityManagerFactory factory = Persistence.createEntityManagerFactory("mysqlJPA");  
  71.         EntityManager em = factory.createEntityManager();  
  72.         Person person = em.getReference(Person.class2); //類似於hibernate的load方法,延遲載入.沒相應資料時會出現異常
  73.         System.out.println(person.getName()); //真正呼叫時才查詢資料
  74.         em.close();  
  75.         factory.close();  
  76.     }  
  77. }  

d)、執行junit測試程式碼裡的相應方法就行可以。