Java Persistence API定義了一種定義,可以將常規的普通Java對象(有時被稱作POJO)映射到數據庫。
這些普通Java對象被稱作Entity Bean。
除了是用Java Persistence元數據將其映射到數據庫外,Entity Bean與其他Java類沒有任何區別。
事實上,創建一個Entity Bean對象相當於新建一條記錄,刪除一個Entity Bean會同時從數據庫中刪除對應記錄,修改一個Entity Bean時,容器會自動將Entity Bean的狀態和數據庫同步。
Java Persistence API還定義了一種查詢語言(JPQL),具有與SQL相類似的特征,只不過做了裁減,以便處理Java對象而非原始的關系表。
hibernate中@Entity和@Table的區別:
@Entity說明這個class是實體類,並且使用默認的orm規則,即class名即數據庫表中表名,class字段名即表中的字段名
如果想改變這種默認的orm規則,就要使用@Table來改變class名與數據庫中表名的映射規則,@Column來改變class中字段名與db中表的字段名的映射規則
@Entity注釋指名這是一個實體Bean,@Table注釋指定了Entity所要映射帶數據庫表,其中@Table.name()用來指定映射表的表名。 如果缺省@Table注釋,系統默認采用類名作為映射表的表名。實體Bean的每個實例代表數據表中的一行數據,行中的一列對應實例中的一個屬性。 @Column注釋定義了將成員屬性映射到關系表中的哪一列和該列的結構信息,屬性如下: 1)name:映射的列名。如:映射tbl_user表的name列,可以在name屬性的上面或getName方法上面加入; 2)unique:是否唯一; 3)nullable:是否允許為空; 4)length:對於字符型列,length屬性指定列的最大字符長度; 5)insertable:是否允許插入; 6)updatetable:是否允許更新; 7)columnDefinition:定義建表時創建此列的DDL; 8)secondaryTable:從表名。如果此列不建在主表上(默認是主表),該屬性定義該列所在從表的名字。 @Id注釋指定表的主鍵,它可以有多種生成方式: 1)TABLE:容器指定用底層的數據表確保唯一; 2)SEQUENCE:使用數據庫德SEQUENCE列萊保證唯一(Oracle數據庫通過序列來生成唯一ID); 3)IDENTITY:使用數據庫的IDENTITY列萊保證唯一; 4)AUTO:由容器挑選一個合適的方式來保證唯一; 5)NONE:容器不負責主鍵的生成,由程序來完成。 @GeneratedValue注釋定義了標識字段生成方式。 @Temporal注釋用來指定java.util.Date或java.util.Calender屬性與數據庫類型date、time或timestamp中的那一種類型進行映射。 @Temporal(value=TemporalType.TIME)
http://blog.csdn.net/lyq123333321/article/details/44217409
@Entity public class Employee implements Serializable { private static final long serialVersionUID = 1L; @Id private Long id; private String name; private int age; private String addree; // Getters and Setters }
如果沒有 @javax.persistence.Entity 和 @javax.persistence.Id 這兩個注解的話,它完全就是一個典型的 POJO 的 Java 類,現在加上這兩個注解之后,就可以作為一個實體類與數據庫中的表相對應。他在數據庫中的對應的表為:
圖 1. Employee 表對應的 ER 圖
映射規則:
1. 實體類必須用 @javax.persistence.Entity 進行注解;
2. 必須使用 @javax.persistence.Id 來注解一個主鍵;
3. 實體類必須擁有一個 public 或者 protected 的無參構造函數,之外實體類還可以擁有其他的構造函數;
4. 實體類必須是一個頂級類(top-level class)。一個枚舉(enum)或者一個接口(interface)不能被注解為一個實體;
5. 實體類不能是 final 類型的,也不能有 final 類型的方法;
6. 如果實體類的一個實例需要用傳值的方式調用(例如,遠程調用),則這個實體類必須實現(implements)java.io.Serializable 接口。
將一個 POJO 的 Java 類映射成數據庫中的表如此簡單,這主要得益於 Java EE 5種引入的 Configuration by Exception 的理念,這個理念的核心就是容器或者供應商提供一個缺省的規則,在這個規則下程序是可以正確運行的,如果開發人員有特殊的需求,需要改變這個默認的規則,那么就是對默認規則來說就是一個異常(Exception)。
如上例所示:默認的映射規則就是數據庫表的名字和對應的 Java 類的名字相同,表中列的名字和 Java 類中相對應的字段的名字相同。
現在我們可以改變這種默認的規則:
清單 2. 使用 @Table 和 @Column 注解修改映射規則
@Entity @Table(name="Workers") public class Employee implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue private Long id; @Column(name="emp_name", length=30) private String name; @Column(name="emp_age", nullable=false) private int age; @Column(name="emp_address", nullable=false ,unique=true) private String addree; // Getters and Setters }
首先我們可以可以使用
@Javax.persistence.Table 這個注解來改變 Java 類在數據庫表種對應的表名。這個注解的定義如下:
從它的定義可以看出他只可以用在類中的方法前面或者字段前面。
其中 name 屬性的值為數據庫中的列名,unique 屬性說明該烈是否唯一,nullable 屬性說明是否可以為空,length 屬性指明了該列的最大長度等等。其中 table 屬性將在 @SecondaryTable 的使用中已有過介紹。
JPA 中兩種注解方式
JPA 中將一個類注解成實體類(entity class)有兩種不同的注解方式:基於屬性(property-based)和基於字段(field-based)的注解。
1,基於字段的注解,就是直接將注解放置在實體類的字段的前面。前面的 Employee 實體類就是使用的這種注解方式;
2,基於屬性的注解,就是直接將注解放置在實體類相應的 getter 方法前面,而不是 setter 方法前面(這一點和 Spring 正好相反)。前面的 Employee 實體類如果使用基於屬性注解的方式就可以寫成如下形式。
但是同一個實體類中必須並且只能使用其中一種注解方式,要么是基於屬性的注解,要么是基於字段的注解。兩種不同的注解方式,在數據庫中對應的數據庫表是相同的,沒有任何區別,開發人員可以根據自己的喜好任意選用其中一種注解方式。
@SecondaryTable 的使用
上面介紹的幾個例子都是一個實體類映射到數據庫中的一個表中,那么能否將一個實體類映射到數據庫兩張或更多表中呢表中呢。在有些情況下如數據庫中已經存在原始數據類型,並且要求不能更改,這個時候如果能實現一個實體類對應兩張或多張表的話,將是很方便的。JPA2.0 中提供了一個 @SecondaryTablez 注解(annotation)就可以實現這種情況。下面用一個例子說明一下這個注解的使用方法:
清單 6. @SecondaryTable 的使用
@Entity @SecondaryTables({ @SecondaryTable(name = "Address"), @SecondaryTable(name = "Comments") }) public class Forum implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue private Long id; private String username; private String password; @Column(table = "Address", length = 100) private String street; @Column(table = "Address", nullable = false) private String city; @Column(table = "Address") private String conutry; @Column(table = "Comments") private String title; @Column(table = "Comments") private String Comments; @Column(table = "Comments") private Integer comments_length; // Getters and Setters }
清單 5 中定義了兩個 Secondary 表,分別為 Address 和 Comments,
同時在 Forum 實體類中也通過 @Column 注解將某些子段分別分配給了這兩張表,那些 table 屬性得值是 Adress 的就會存在於 Address 表中,
同理 table 屬性的值是 Comments 的就會存在於 Comments 表中。那些沒有用 @Column 注解改變屬性默認的字段將會存在於 Forum 表中。
圖 4 就是持久化后在數據庫中對應的表的 ER 圖,從圖中可看出來,這些字段如我們預料的一樣被映射到了不同的表中。
圖 4. @SecondaryTable 持久化后對贏得 ER 圖
嵌套映射
在使用嵌套映射的時候首先要有一個被嵌套的類,清單 5 中 Address 實體類使用 @Embeddable 注解,說明這個就是一個可被嵌套的類,與 @EmbeddedId 復合主鍵策略中的主鍵類(primary key class)稍有不同的是,這個被嵌套類不用重寫 hashCode() 和 equals() 方法,復合主鍵將在后面進行介紹。
清單 7. 被嵌套類
@Embeddable public class Address implements Serializable { private String street; private String city; private String province; private String country; // Getters and Setters }
清單 6 中 Employee 實體類是嵌套類的擁有者,其中使用了 @Embedded 注解將 Address 類嵌套進來了。
清單 8. 嵌套類的使用者
@Entity public class Employee implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; private String email; private String cellPhone; @Embedded private Address address; // Getters and Setters }
清單 7 是持久化后生成的數據庫表,可以看出被嵌套類的屬性,也被持久化到了數據庫中,默認的表名就是嵌套類的擁有者的類名。
清單 9. 使用嵌套類生成的表結構
CREATE TABLE `employee` ( `ID` bigint(20) NOT NULL, `EMAIL` varchar(255) default NULL, `NAME` varchar(255) default NULL, `CELLPHONE` varchar(255) default NULL, `STREET` varchar(255) default NULL, `PROVINCE` varchar(255) default NULL, `CITY` varchar(255) default NULL, `COUNTRY` varchar(255) default NULL, PRIMARY KEY (`ID`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
被嵌套類的注解方式,field 方式或者 property 方式,依賴於嵌套類的擁有者。上面例子中的 Employee 實體類采用的是 field 注解方式,那么在持久化的過程中,被嵌套類 Address 也是按照 field 注解方式就行映射的。
我們也可以通過 @Access 注解改變被嵌套類映射方式,清單 8 通過使用 @Access 注解將 Address 被嵌套類的注解方式設定成了 property 方式。清單 9 Employee 仍然采用 filed 注解方式。這種情況下,持久化的時候,被嵌套類就會按照自己設定的注解方式映射,而不會再依賴於嵌套類的擁有者的注解方式。但這並不會映射的結果。
清單 10. 基於 property 方式注解的被嵌套類
@Embeddable @Access(AccessType.PROPERTY) public class Address implements Serializable { private String street; private String city; private String province; private String country; @Column(nullable=false) public String getCity() { return city; } public void setCity(String city) { this.city = city; } @Column(nullable=false,length=50) public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } @Column(nullable=false,length=20) public String getProvince() { return province; } public void setProvince(String province) { this.province = province; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } }
清單 11. 基於 field 方式注解
@Entity @Access(AccessType. FIELD) public class Employee implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; private String email; private String cellPhone; @Embedded private Address address; // Getters and Setters }
事先設定被嵌套類的注解方式,是一種應該大力提倡的做法,因為當同一個類被不同的注解方式的類嵌套時,可能會出現一些錯誤。
總結
簡單映射是 ORM,也就是對象關系映射中較為簡單的一種,他只是數據庫表與類之間的一一對應,並未涉及表之間的關系,也就未涉及類與類之間的關系,也可以說是其他如繼承映射,關聯關系映射的基礎,所以說熟悉並掌握簡單關系映射還是很有必要的。
- JSR 3170:JavaTM Persistence API,Version 2.0。 JPA 全稱 Java Persistence API,JPA 由 EJB 3.0 軟件專家組開發,作為 JSR-220 實現的一部分。但它不囿於 EJB 3.0,你可以在 Web 應用、甚至桌面應用中使用。JPA 的宗旨是為 POJO 提供持久化標准規范。
- Hibernate:Java 對象持久化技術詳解: Hibernate 是一個開放源代碼的 ORM(對象關系映射)框架,它對 JDBC 進行了非常輕量級的對象封裝,使得 Java 程序員可以隨心所欲的使用對象編程思維來操縱數據庫。
- developerWorks Java 技術專區:這里有數百篇關於 Java 編程各個方面的文章。
討論
- 加入 developerWorks 中文社區:查看開發人員推動的博客、論壇、組和維基,並與其他 developerWorks 用戶交流。
http://www.ibm.com/developerworks/cn/java/j-lo-jpasimpemap/
Hibernate中關於@MappedSuperclass和@Entity的區別
package com.entity.base; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.MappedSuperclass; @MappedSuperclass public class BaseEntity { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Integer id;
如果上訴代碼中在使用@MappedSuperclass標簽的地方使用了@Entity標簽的話,
會讓hibernate錯誤的認為所有的Entity都是在一張數據表中的。
http://www.voidcn.com/blog/kunshan_shenbin/article/p-4753265.html
JPA Java Persistence API,是Java EE 5的標准ORM接口,也是ejb3規范的一部分。
Hibernate,當今很流行的ORM框架,是JPA的一個實現,但是其功能是JPA的超集。
JPA和Hibernate之間的關系,可以簡單的理解為JPA是標准接口,Hibernate是實現。那么Hibernate是如何實現與JPA的這種關系的呢。Hibernate主要是通過三個組件來實現的,及hibernate-annotation、hibernate-entitymanager和hibernate-core。
hibernate-annotation是Hibernate支持annotation方式配置的基礎,它包括了標准的JPA annotation以及Hibernate自身特殊功能的annotation。
hibernate-core是Hibernate的核心實現,提供了Hibernate所有的核心功能。
hibernate-entitymanager實現了標准的JPA,可以把它看成hibernate-core和JPA之間的適配器,它並不直接提供ORM的功能,而是對hibernate-core進行封裝,使得Hibernate符合JPA的規范。
Jpa是一種規范,而Hibernate是它的一種實現。除了Hibernate,還有EclipseLink(曾經的toplink),OpenJPA等可供選擇,所以使用Jpa的一個好處是,可以更換實現而不必改動太多代碼。
在play中定義Model時,使用的是jpa的annotations,比如javax.persistence.Entity, Table, Column, OneToMany等等。但它們提供的功能基礎,有時候想定義的更細一些,難免會用到Hibernate本身的annotation。我當時想,jpa這么弱還要用它干什么,為什么不直接使用hibernate的?反正我又不會換成別的實現。
因為我很快決定不再使用hibernate,這個問題就一直放下了。直到我現在在新公司,做項目要用到Hibernate。
我想拋開jpa,直接使用hibernate的注解來定義Model,很快發現了幾個問題:
- jpa中有Entity, Table,hibernate中也有,但是內容不同
- jpa中有Column,OneToMany等,Hibernate中沒有,也沒有替代品
我原以為hibernate對jpa的支持,是另提供了一套專用於jpa的注解,但現在看起來似乎不是。一些重要的注解如Column, OneToMany等,hibernate沒有提供,這說明jpa的注解已經是hibernate的核心,hibernate只提供了一些補充,而不是兩套注解。要是這樣,hibernate對jpa的支持還真夠足量,我們要使用hibernate注解就必定要使用jpa。
實際情況是不是這樣?在被群里(Scala交流群132569382)的朋友鄙視一番卻沒有給出滿意答案的時候,我又想起了萬能的stackoverflow,上去提了兩個問:
- http://stackoverflow.com/questions/8306742/if-i-want-to-use-hibernate-with-annotation-do-i-have-to-use-javax-persistence
- http://stackoverflow.com/questions/8306793/why-jpa-and-hibernate-both-have-entity-and-table-annotations
第一個是問如果想用hibernate注解,是不是一定會用到jpa的。網友的回答:“是。如果hibernate認為jpa的注解夠用,就直接用。否則會弄一個自己的出來作為補充”
第二個是問,jpa和hibernate都提供了Entity,我們應該用哪個,還是說可以兩個一起用?網友回答說“Hibernate的Entity是繼承了jpa的,所以如果覺得jpa的不夠用,直接使用hibernate的即可”。