posts - 78, comments - 34, trackbacks - 0, articles - 1
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          2010-01-19 傳智播客—JPA

          Posted on 2010-01-19 23:46 長城 閱讀(583) 評論(0)  編輯  收藏

          今后三天的課程內容為:JPAEJB。我們的班型是JAVAEE精品就業班,我們學習的是JAVAEE嗎?JAVAEE是分布式企業級應用,我們之前學習的JSPServlet都是JAVAEE的內容,是基礎內容。那么JAVAEE的核心是什么?沒有學習JAVAEE的核心還算是學習過JAVAEE嗎?JAVAEE的核心是EJB

          EJB具體是做什么的?目前還不清楚,這部分內容在明天和后天會學習。今日的重點內容是JPA,什么是JPA呢?JPAEJB3中持久化部分。

           Sun引入新的JPA ORM規范出于兩個原因:其一,簡化現有Java EEJava SE應用的對象持久化的開發工作;其二,Sun希望整合對ORM技術,實現天下歸一。

            JPAEJB 3.0軟件專家組開發,作為JSR-220實現的一部分。但它不囿于EJB 3.0,你可以在Web應用、甚至桌面應用中使用。JPA的宗旨是為POJO提供持久化標準規范,由此可見,經過這幾年的實踐探索,能夠脫離容器獨立運行,方便開發和測試的理念已經深入人心了。目前Hibernate 3.2TopLink 10.1.3以及OpenJPA都提供了JPA的實現。

            JPA的總體思想和現有HibernateTopLinkJDOORM框架大體一致。

          一、搭建JPA環境

          我們之前已經學習過Hibernate,學習JPA就比較容易了。因為HibernateJPA的一種實現。

          1.創建一個普通的JAVA工程。

          2.導入“hibernate-distribution-3.3.1.GA\jpa”目錄下的所有Jar包,還有數據庫驅動包。我們使用的是MySQL

          3.在“SRC”上右鍵創建一個“META-INF”目錄,“META-INF”實際位置在classpath下。

          4.在“META-INF”目錄中添加一個“persistence.xml”文件,這個是JPA的配置文件哦。文件內容:

          <?xml version="1.0"?>

          <persistence xmlns="http://java.sun.com/xml/ns/persistence"

           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

           xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"

           version="1.0">

          <persistence-unit name="jpa" transaction-type="RESOURCE_LOCAL">

          <class>cn.itcast.cc.jpa.entity.Customer</class>

          <!-- JPA實現,使用hibernate -->

          <properties>

          <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>

          <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/jpa"/>

          <property name="hibernate.connection.username" value="root"/>

          <property name="hibernate.connection.password" value="root"/>

          <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>

          <property name="hibernate.hbm2ddl.auto" value="create"/>

          <property name="hibernate.show_sql" value="true"/>

          </properties>

          </persistence-unit>

          </persistence>

          5.創建“cn.itcast.cc.jpa.entity.Customer”實體類:

          package cn.itcast.cc.jpa.entity;

          import javax.persistence.Entity;

          import javax.persistence.GeneratedValue;

          import javax.persistence.Id;

          @Entity // 必須指定

          public class Customer {

          @Id // 必須指定

          @GeneratedValue

          private Integer id;

          private String name;

          // getters And setters...

          }

          其中“@Entity”與“@Id”必須指定,JPA通過這些注解生成相應的表和字段。加在屬性上的注解也可以加在屬性的gettersetter方法。這些用于設置字段的注解,要么全加在屬性上,要么全加在屬性方法上。JPA以“@Id”所在位置為參照,判斷應該使用屬性上的注解還是屬性方法上的注解。

          6.編寫測試類:

          package cn.itcast.cc.jpa;

          import javax.persistence.EntityManager;

          import javax.persistence.EntityManagerFactory;

          import javax.persistence.EntityTransaction;

          import javax.persistence.Persistence;

          import cn.itcast.cc.jpa.entity.Customer;

          public class App {

          public static void main(String[] args){

          // 創建實體管理對象工廠,相當于HiberanteSessionFactory

          EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa");

          // 創建實體管理對象,相當于HiberanteSession

          EntityManager em = emf.createEntityManager();

          // 獲取實體事務對象

          EntityTransaction et = em.getTransaction();

          // 開始事務

          et.begin();

          // 創建Customer實體對象

          Customer customer = new Customer();

          customer.setName("changcheng");

          // 持久化customer實體對象(保存)

          em.persist(customer);

          // 提交事務

          et.commit();

          // 關閉

          em.close();

          emf.close();

          }

          }

          Very簡單吧!強悍的地方是我們可以將hibernate更換為其他實現了JPA接口的框架,然后修改一個persistence.xml文件的配置信息,其他地方無需修改。

          二、JPACURD

          JPACURDHibernateCURD操作不大相似,但也十分簡單。

          1.插入記錄

          上邊的例子,我們正是使用到插入的方法,將實體保存到數據庫:

          @Test

          public void create(){

          EntityManager em = emf.createEntityManager();

          EntityTransaction et = em.getTransaction();

          et.begin();

          Customer customer = new Customer();

          customer.setName("china");

          // 保存到數據庫

          em.persist(customer);

          et.commit();

          em.close();

          emf.close();

          }

          2.更新記錄

          JPA中沒有update方法,我們需要先取出記錄。然后再對記錄進行修改,持久化對象可以自動更新到數據庫中。

          @Test

          public void update(){

          EntityManager em = emf.createEntityManager();

          EntityTransaction et = em.getTransaction();

          et.begin();

               // 查詢數據

          Customer customer = em.find(Customer.class, new Integer(1));

          // 更新數據

          customer.setName("new name");

          et.commit();

          em.close();

          emf.close();

          }

          還可以使用“customer = em.getReference(Customer.class, new Integer(1));”。find方法相當于Hibernateget方法,getReference相當于Hibernateload方法。

          3.查詢記錄

          查詢可以使用findgetReference方法,這里不列出了。

          4.刪除記錄

          JPA有一個remove方法,用來刪除查詢到的實體。

          @Test

          public void remove(){

          EntityManager em = emf.createEntityManager();

          EntityTransaction et = em.getTransaction();

          et.begin();

          // 查詢數據

          Customer customer = em.getReference(Customer.class, new Integer(1));

          // 刪除數據

          em.remove(customer);

          et.commit();

          em.close();

          emf.close();

          }

          JPA還有一個Merge的方法,用于同步游離狀態。“cus = em.merge(customer); merge返回的cus為緩存中持久化對象的引用,customer則不是。

          三、JPA中的注解

          我們在學習hibernate時使用entity.hbm.xml映射文件,描述對象與對象的關系,對象與數據表格的配置。那是一件十分郁悶的工作,JPA中支持使用注解描述以上關系,Hibernate也支持。使用注解描述,更直觀、簡單。

          1.Table

          Table用來定義entity主表的namecatalogschema等屬性。

          元數據屬性說明:

          · name: 表名

          · catalog: 對應關系數據庫中的catalog

          · schema:對應關系數據庫中的schema

          · UniqueConstraints:定義一個UniqueConstraint數組,指定需要建唯一約束的列

          2.SecondaryTable

          一個entity class可以映射到多表,SecondaryTable用來定義單個從表的名字,主鍵名字等屬性。使用SecondaryTable可以實現一對一關系的主鍵關聯。

          元數據屬性說明:

          · name: 表名

          · catalog: 對應關系數據庫中的catalog

          · schema:對應關系數據庫中的schema

          · pkJoin: 定義一個PrimaryKeyJoinColumn數組,指定從表的主鍵列

          · UniqueConstraints:定義一個UniqueConstraint數組,指定需要建唯一約束的列

          下面的代碼說明Customer類映射到兩個表,主表名是CUSTOMER,從表名是CUST_DETAIL,從表的主鍵列和主表的主鍵列類型相同,列名為CUST_ID

          @Entity

          @Table(name="CUST")

          public class Customer { ... }

          3.SecondaryTables

          當一個entity class映射到一個主表和多個從表時,用SecondaryTables來定義各個從表的屬性。

          元數據屬性說明:

          · value: 定義一個SecondaryTable數組,指定每個從表的屬性。

          @Entity

          @Table(name="CUSTOMER")

          @SecondaryTable(name="CUST_DETAIL",pkJoin=@PrimaryKeyJoinColumn(name="CUST_ID"))

          public class Customer { ... }

          4.UniqueConstraint

          UniqueConstraint定義在TableSecondaryTable元數據里,用來指定建表時需要建唯一約束的列。

          元數據屬性說明:

          · columnNames:定義一個字符串數組,指定要建唯一約束的列名。

          @Table(name = "CUSTOMER")

          @SecondaryTables(value = {

          @SecondaryTable(name = "CUST_NAME", pkJoin = { @PrimaryKeyJoinColumn(name = "STMO_ID", referencedColumnName = "id") }),

          @SecondaryTable(name = "CUST_ADDRESS", pkJoin = { @PrimaryKeyJoinColumn(name = "STMO_ID", referencedColumnName = "id") }) })

          public class Customer {}

          5.Column

          Column元數據定義了映射到數據庫的列的所有屬性:列名,是否唯一,是否允許為空,是否允許更新等。

          元數據屬性說明:

          · name:列名。

          · unique: 是否唯一

          · nullable: 是否允許為空

          · insertable: 是否允許插入

          · updatable: 是否允許更新

          · columnDefinition: 定義建表時創建此列的DDL

          · secondaryTable: 從表名。如果此列不建在主表上(默認建在主表),該屬性定義該列所在從表的名字。

          @Entity

          @Table(name="EMPLOYEE", uniqueConstraints={@UniqueConstraint(columnNames={"EMP_ID", "EMP_NAME"})})

          public class Employee { ... }

          6.JoinColumn

          如果在entity classfield上定義了關系(one2oneone2many等),我們通過JoinColumn來定義關系的屬性。JoinColumn的大部分屬性和Column類似。

          元數據屬性說明:

          · name:列名。

          · referencedColumnName:該列指向列的列名(建表時該列作為外鍵列指向關系另一端的指定列)

          · unique: 是否唯一

          · nullable: 是否允許為空

          · insertable: 是否允許插入

          · updatable: 是否允許更新

          · columnDefinition: 定義建表時創建此列的DDL

          · secondaryTable: 從表名。如果此列不建在主表上(默認建在主表),該屬性定義該列所在從表的名字。

          下面的代碼說明CustomOrder是一對一關系。在Order對應的映射表建一個名為CUST_ID的列,該列作為外鍵指向Custom對應表中名為ID的列。

          public class Person {

          @Column(name = "PERSONNAME", unique = true, nullable = false, updatable = true)

          private String name;

          @Column(name = "PHOTO", columnDefinition = "BLOB NOT NULL", secondaryTable = "PER_PHOTO")

          private byte[] picture;

          }

          7.JoinColumns

          如果在entity classfield上定義了關系(one2oneone2many等),并且關系存在多個JoinColumn,用JoinColumns定義多個JoinColumn的屬性。

          元數據屬性說明:

          · value: 定義JoinColumn數組,指定每個JoinColumn的屬性。

          下面的代碼說明CustomOrder是一對一關系。在Order對應的映射表建兩列,一列名為CUST_ID,該列作為外鍵指向Custom對應表中名為ID的列,另一列名為CUST_NAME,該列作為外鍵指向Custom對應表中名為NAME的列。

          public class Custom {

          @OneToOne

          @JoinColumn(name = "CUST_ID", referencedColumnName = "ID", unique = true, nullable = true, updatable = true)

          public Order getOrder() {

          return order;

          }

          }

          8.Id

          聲明當前field為映射表中的主鍵列。id值的獲取方式有五種:TABLE, SEQUENCE, IDENTITY, AUTO, NONEOracleDB2支持SEQUENCESQL ServerSybase支持IDENTITY,mysql支持AUTO。所有的數據庫都可以指定為AUTO,我們會根據不同數據庫做轉換。NONE (默認)需要用戶自己指定Id的值。元數據屬性說明:

          · generate():主鍵值的獲取類型

          · generator():TableGenerator的名字(當generate=GeneratorType.TABLE才需要指定該屬性)

          下面的代碼聲明Task的主鍵列id是自動增長的。(OracleDB2從默認的SEQUENCE取值,SQL ServerSybase該列建成IDENTITYmysql該列建成auto increment)

          public class Custom {

          @OneToOne

          @JoinColumns( { @JoinColumn(name = "CUST_ID", referencedColumnName = "ID"),

          @JoinColumn(name = "CUST_NAME", referencedColumnName = "NAME") })

          public Order getOrder() {

          return order;

          }

          }

          9.IdClass

          entity class使用復合主鍵時,需要定義一個類作為id classid class必須符合以下要求:類必須聲明為public,并提供一個聲明為public的空構造函數。必須實現Serializable接,覆寫 equals()hashCode()方法。entity class的所有id fieldid class都要定義,且類型一樣。

          元數據屬性說明:

          · value: id class的類名

          @Entity

          @Table(name = "OTASK")

          public class Task {

          @Id(generate = GeneratorType.AUTO)

          public Integer getId() {

          return id;

          }

          }

          public class EmployeePK implements java.io.Serializable {

          String empName;

          Integer empAge;

          public EmployeePK() {......}

          public boolean equals(Object obj){......}

          public int hashCode(){......}

          }

          @IdClass(value = com.acme.EmployeePK.class)

          @Entity(access = FIELD)

          public class Employee {

          @Id

          String empName;

          @Id

          Integer empAge;

          }

          10.MapKey

          在一對多,多對多關系中,我們可以用Map來保存集合對象。默認用主鍵值做key,如果使用復合主鍵,則用id class的實例做key,如果指定了name屬性,就用指定的field的值做key

          元數據屬性說明:

          · name: 用來做keyfield名字

          下面的代碼說明PersonBook之間是一對多關系。Personbooks字段是Map類型,用Bookisbn字段的值作為Mapkey

          11.OrderBy

          在一對多,多對多關系中,有時我們希望從數據庫加載出來的集合對象是按一定方式排序的,這可以通過OrderBy來實現,默認是按對象的主鍵升序排列。

          元數據屬性說明:

          · value: 字符串類型,指定排序方式。格式為"fieldName1 [ASC|DESC],fieldName2 [ASC|DESC],......",排序類型可以不指定,默認是ASC

          下面的代碼說明PersonBook之間是一對多關系。集合books按照Bookisbn升序,name降序排列。

          12.PrimaryKeyJoinColumn

          在三種情況下會用到PrimaryKeyJoinColumn

          · 繼承。

          · entity class映射到一個或多個從表。從表根據主表的主鍵列(列名為referencedColumnName值的列),建立一個類型一樣的主鍵列,列名由name屬性定義。

          · one2one關系,關系維護端的主鍵作為外鍵指向關系被維護端的主鍵,不再新建一個外鍵列。

          元數據屬性說明:

          · name:列名。

          · referencedColumnName:該列引用列的列名

          · columnDefinition: 定義建表時創建此列的DDL

          下面的代碼說明Customer映射到兩個表,主表CUSTOMER,從表CUST_DETAIL,從表需要建立主鍵列CUST_ID,該列和主表的主鍵列id除了列名不同,其他定義一樣。

          @Table(name = "PERSON")

          public class Person {

          @OneToMany(targetEntity = Book.class, cascade = CascadeType.ALL, mappedBy = "person")

          @MapKey(name = "isbn")

          private Map books = new HashMap();

          }

          @Table(name = "MAPKEY_PERSON")

          public class Person {

          @OneToMany(targetEntity = Book.class, cascade = CascadeType.ALL, mappedBy = "person")

          @OrderBy(name = "isbn ASC, name DESC")

          private List books = new ArrayList();

          }

          下面的代碼說明EmployeeEmployeeInfo是一對一關系,Employee的主鍵列id作為外鍵指向EmployeeInfo的主鍵列INFO_ID

          13.PrimaryKeyJoinColumns

          如果entity class使用了復合主鍵,指定單個PrimaryKeyJoinColumn不能滿足要求時,可以用PrimaryKeyJoinColumns來定義多個PrimaryKeyJoinColumn

          元數據屬性說明:

          · value: 一個PrimaryKeyJoinColumn數組,包含所有PrimaryKeyJoinColumn

          下面的代碼說明了EmployeeEmployeeInfo是一對一關系。他們都使用復合主鍵,建表時需要在Employee表建立一個外鍵,從Employee的主鍵列id,name指向EmployeeInfo的主鍵列INFO_IDINFO_NAME

          @Entity

          @Table(name="CUSTOMER")

          @SecondaryTable(name="CUST_DETAIL",pkJoin=@PrimaryKeyJoinColumn(name="CUST_ID"referencedColumnName="id"))

          public class Customer {

          @Id(generate = GeneratorType.AUTO)

          public Integer getId() {

          return id;

          }

          }

          @Table(name = "Employee")

          public class Employee {

          @OneToOne

          @PrimaryKeyJoinColumn(name = "id", referencedColumnName = "INFO_ID")

          EmployeeInfo info;

          }

          @Entity

          @IdClass(EmpPK.class)

          @Table(name = "EMPLOYEE")

          public class Employee {

          private int id;

          private String name;

          private String address;

          @OneToOne(cascade = CascadeType.ALL)

          @PrimaryKeyJoinColumns( {

          @PrimaryKeyJoinColumn(name = "id", referencedColumnName = "INFO_ID"),

          @PrimaryKeyJoinColumn(name = "name", referencedColumnName = "INFO_NAME") })

          EmployeeInfo info;

          }

          @Entity

          @IdClass(EmpPK.class)

          @Table(name = "EMPLOYEE_INFO")

          public class EmployeeInfo {

          @Id

          @Column(name = "INFO_ID")

          private int id;

          @Id

          @Column(name = "INFO_NAME")

          private String name;

          }

          14.Transient

          Transient用來注釋entity的屬性,指定的這些屬性不會被持久化,也不會為這些屬性建表。

          15.Version

          Version指定實體類在樂觀事務中的version屬性。在實體類重新由EntityManager管理并且加入到樂觀事務中時,保證完整性。每一個類只能有一個屬性被指定為versionversion屬性應該映射到實體類的主表上。

          下面的代碼說明versionNum屬性作為這個類的version,映射到數據庫中主表的列名是OPTLOCK

          16.Lob

          Lob指定一個屬性作為數據庫支持的大對象類型在數據庫中存儲。使用LobType這個枚舉來定義Lob是二進制類型還是字符類型。

          LobType枚舉類型說明:

          · BLOB 二進制大對象,Byte[]或者Serializable的類型可以指定為BLOB

          · CLOB 字符型大對象,char[]Character[]String類型可以指定為CLOB

          元數據屬性說明:

          · fetch: 定義這個字段是lazy loaded還是eagerly fetched。數據類型是FetchType枚舉,默認為LAZY,lazy loaded.

          · type: 定義這個字段在數據庫中的JDBC數據類型。數據類型是LobType枚舉,默認為BLOB

          下面的代碼定義了一個BLOB類型的屬性和一個CLOB類型的屬性。

          17.JoinTable

          JoinTablemany-to-many關系的所有者一邊定義。如果沒有定義JoinTable,使用JoinTable的默認值。

          元數據屬性說明:

          · table:這個join tableTable定義。

          · joinColumns:定義指向所有者主表的外鍵列,數據類型是JoinColumn數組。

          · inverseJoinColumns:定義指向非所有者主表的外鍵列,數據類型是JoinColumn數組。

          下面的代碼定義了一個連接表CUSTPHONEjoin tablejoin table的表名是CUST_PHONE,包含兩個外鍵,一個外鍵是CUST_ID,指向表CUST的主鍵ID,另一個外鍵是PHONE_ID,指向表PHONE的主鍵ID

          18.TableGenerator

          TableGenerator定義一個主鍵值生成器,在Id這個元數據的generateTABLE時,generator屬性中可以使用生成器的名字。生成器可以在類、方法或者屬性上定義。

          生成器是為多個實體類提供連續的ID值的表,每一行為一個類提供ID值,ID值通常是整數。

          元數據屬性說明:

          · name:生成器的唯一名字,可以被Id元數據使用。

          · table:生成器用來存儲id值的Table定義。

          · pkColumnName:生成器表的主鍵名稱。

          · valueColumnName:生成器表的ID值的列名稱。

          · pkColumnValue:生成器表中的一行數據的主鍵值。

          · initialValue:id值的初始值。

          · allocationSize:id值的增量。

          下面的代碼定義了兩個生成器empGenaddressGen,生成器的表是ID_GEN

          @Transient

          private String name;

          @Version

          @Column("OPTLOCK")

          protected int getVersionNum() { return versionNum; }

          @Lob

          @Column(name="PHOTO" columnDefinition="BLOB NOT NULL")

          protected JPEGImage picture;

          @Lob(fetch=EAGER, type=CLOB)

          @Column(name="REPORT")

          protected String report;

          19.SequenceGenerator

          SequenceGenerator定義一個主鍵值生成器,在Id這個元數據的generator屬性中可以使用生成器的名字。生成器可以在類、方法或者屬性上定義。生成器是數據庫支持的sequence對象。

          元數據屬性說明:

          · name:生成器的唯一名字,可以被Id元數據使用。

          · sequenceName:數據庫中,sequence對象的名稱。如果不指定,會使用提供商指定的默認名稱。

          · initialValue:id值的初始值。

          · allocationSize:id值的增量。

          下面的代碼定義了一個使用提供商默認名稱的sequence生成器。

          20.DiscriminatorColumn

          DiscriminatorColumn定義在使用SINGLE_TABLEJOINED繼承策略的表中區別不繼承層次的列。

          元數據屬性說明:

          · name:column的名字。默認值為TYPE

          · columnDefinition:生成DDLsql片斷。

          · length:String類型的column的長度,其他類型使用默認值10

          下面的代碼定義了一個列名為DISC,長度為20String類型的區別列。

          @JoinTable(table = @Table(name = CUST_PHONE), joinColumns = @JoinColumn(name = "CUST_ID", referencedColumnName = "ID"), inverseJoinColumns = @JoinColumn(name = "PHONE_ID", referencedColumnName = "ID"))

          @Entity

          public class Employee {

          // ...

          @TableGenerator(name = "empGen", table = @Table(name = "ID_GEN"), pkColumnName = "GEN_KEY", valueColumnName = "GEN_VALUE", pkColumnValue = "EMP_ID", allocationSize = 1)

          @Id(generate = TABLE, generator = "empGen")

          public int id;

          // ...

          }

          @Entity

          public class Address {

          // ...

          @TableGenerator(name = "addressGen", table = @Table(name = "ID_GEN"), pkColumnValue = "ADDR_ID")

          @Id(generate = TABLE, generator = "addressGen")

          public int id;

          // ...

          }

          這部分資料并非本人一一總結,而是取自互聯網。

          其中有一部分的內容,在明天的課程中才會講到。


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 定远县| 武城县| 阳朔县| 旺苍县| 南郑县| 青海省| 渭源县| 芜湖县| 宁安市| 塘沽区| 安丘市| 元谋县| 疏附县| 高雄县| 潜山县| 阳新县| 德阳市| 兴安县| 陆丰市| 南丹县| 余庆县| 什邡市| 乐安县| 柯坪县| 兴义市| 金坛市| 苗栗市| 砚山县| 南乐县| 教育| 营山县| 罗山县| 武冈市| 定南县| 汝南县| 子洲县| 邮箱| 哈巴河县| 虎林市| 宾川县| 榕江县|