JPA註解的使用,用於實體類的註解
1、 @Entity(name=”EntityName”)
表示該類是一個可持化的實體。當在容器中時,伺服器將會首先載入所有標註了@Entity註釋的實體類,其中@Entity中的“name”屬性表示實體名稱,若不作設定,預設為標註實體類的名稱(注意大小寫與系統的關係。)。 @Entity標註是必需的 ,name屬性為可選。
Java程式碼- @Entity(name=“person_1”)
- public class Person implements Serializable {
- public Person(){
-
id=System.currentTimeMillis();
- }
- public Person(Long id){
- this.id = id;
- }
- }
@Entity標註的實體類至少需要有一個無參的構造方法。這是因為,在使用類反射機制 Class.newInstance()方法建立例項時,必需要有一個預設的無引數構造方法,否則會執出例項化異常(InstantiationException)。
如果指定name屬性後,在執行JPQL時應該使用name屬性所指的名稱。像上面的標註後,在執行JPQL時要像下面這樣:
Sql程式碼-
SELECT p FROM person_1 AS
name屬性為預設值時就使用類名稱:
Sql程式碼- SELECT p FROM Person AS p;
有兩點須要注意:
(1)實體可繼承,非實體類可以繼承自實體類,實體類也要中以繼承自非實類。
(2)抽象類(abstract)也可以標註為實體類。
2、@Table
在使用@Table標記時,需要注意以下幾個問題。
(1) 此標記需要標註在類名前,不能標註在方法或屬性前。
(2) name 屬性表示實體所對應表的名稱,預設表名為實體名稱。
(3) catalog
(4) uniqueConstraints 屬性表示該實體所關聯的唯一約束條件,一個實體可以有多個唯一的約束,預設沒有約束條件。
(5)若使用uniqueContraints 屬性時,需要配合標記UniqueContraint標記來使用。
Java程式碼- package model;
- import java.io.Serializable;
- import javax.persistence.Entity;
- import javax.persistence.Table;
- import javax.persistence.UniqueConstraint;
- @Entity
- @Table(name = “tb_contact”, schema = “test”, uniqueConstraints = {
- @UniqueConstraint(columnNames = {“name”, “email” }),
- @UniqueConstraint(columnNames = {“col1”, “col2” })
- })
- public class ContactEO implements Serializable {
- private Long id;
- private String name;
- private String email;
- private String col1;
- private String col2;
- }
以上的@Table註釋表示指定資料庫名“test”,表名為“tb_contact”,並建立了兩組唯一索引。
3、@Column
@Column標記表示持久化屬性對映表中的欄位。此標記可以標註在Getter方法或屬性前。
如標註在屬性前
Java程式碼- public class ContactEO implements Serializable {
- @Column(name = “name”)
- private String name;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
或者標註在Getter方法前。
Java程式碼- public class ContactEO implements Serializable {
- private String name;
- @Column(name = “name”)
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
(1) unique 屬性表示該欄位是否為唯一標識,預設為false。如果表中有一個欄位需要唯一標識,則既可以使用@Column標記也可以使用@Table標記中的@UniqueConstraint。
(2)nullable 屬性表示該欄位是否可以為null值,預設為true(允許為null值)。
(3)insertable 屬性表示在使用“INSERT” SQL語指令碼插入資料時,是否需要插入該欄位的值。
(4)updatable 屬性表示在使用“UPDATE”指令碼插入資料時,是否需要更新該欄位的值。insertable和updatable屬性一般多用於只讀屬性,例如主鍵和外來鍵等。這些欄位值通常是自動生成的。
(5)columnDefinition 屬性表示建立表時,該欄位建立的SQL語句,一般用於通過Entity生成表定義時使用。
(6)table 屬性表示當對映多個表時,指定表中的欄位。預設值為主表的表名。
(7)length 屬性表示該欄位的長度,當欄位的型別為varchar時,該屬性才有效,預設為255個字元。
(8)precision 屬性和scale 屬性表示精度,當欄位型別為double時,precision表示數值的總長度,scale表示小數點所佔的位數。
示例一、
Java程式碼- private String name;
- @Column(name = “name”,nullable=false,length=512)
- public String getName() {
- return name;
- }
生成的SQL指令碼為
Java程式碼- CREATE TABLE contact(
- id integer not null,
- name varchar(512) not null,
- primary key(id)
- );
示例二、為double型指定精度為12位,小數點位數為2位。
Java程式碼- private BigDecimal monthlyIncome;
- @Column(name=“monthly_income”,precision=12,scale=2)
- public BigDecimal getMonthlyIncome() {
- return monthlyIncome;
- }
- public void setMonthlyIncome(BigDecimal monthlyIncome) {
- this.monthlyIncome = monthlyIncome;
- }
生成的SQL指令碼為
Java程式碼- CREATE TABLE contact(
- id integer not null,
- monthly_income double(12,2),
- primary key(id)
- );
示例三、自定義生成CLOB型別欄位的SQL語句
Java程式碼- @Column(name = “contact_name”,columnDefinition=“ clob not null” )
- private String name;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
生成的SQL指令碼為
Sql程式碼- CREATE TABLE contact(
- id integer not null,
- contact_name <strong>clob(200) not null,</strong>
- primary key(id)
- );
其中加粗的部份為columnDefinition屬性設定的值。若不指定該屬笥,通常使用預設的型別建表,若此時需要自定義建表的型別時,可以在該屬性設定。
可持久化的資料型別
分類 | 型別 |
Java的基本資料型別 | byte、int、short、long、boolean、char、float、double |
Java的基本資料型別對應的封裝類 | Byte、Int、Short、Long、Boolean、Character、Float、Double |
位元組和字元型陣列 | byte[]、Byte[]、char[]、Character[] |
大數值型別 |
Java.math.BigInteger java.math.BigDecimal |
字串型別 | java.lang.String |
日期時間型別 |
java.util.Date java.util.Calendar java.sql.Date java.sql.Time java.sql.Timestamp |
列舉型 | 使用者自定義的列舉型 |
Entity型別 | 標註為@Entity的類 |
包含Entity型別的集合Collection類 |
java.util.Collection java.util.Set java.util.List java.util.Map |
嵌入式(embeddable)類 |
Java資料型別與資料庫中的型別轉換是由JPA實現框架自動轉換的,所以不同的JPA實現框架轉換的規則也不太一樣。
例如MySQL中,varchar和char型別都轉化為String型別。Blob和Clob型別可以轉化成Byte[]型。由於型別轉化是JPA底層來實現的,這就遇到一個問題,很有可能在將表中的資料轉換成Java的資料型別時出現異常。
我們知道對於可以持久化的Java型別中,即可以對映基本的資料型別,如byte、int、short、long、boolean、char、float、double等,也可以對映成 Byte、Int、Short、Long、Boolean、Character、Float、 Double型別。那麼選擇哪種型別比較合適呢?
舉下面的例子進行說明。
Sql程式碼- CREATE TABLE contact(
- id integer not null,
- monthly_income double(12,2),
- primary key(id)
- );
對於表字段id,它的值不能為null,所以對映成int型和Integer型都是可以的。
但對於表字段monthly_income來說,它的值可能為null。當為null時,若此時java的Enity類的對應屬性的型別int,則將一個null值轉化成int型必定產生轉換異。但此時java的Entity類對應的屬性為Integer,它是一個物件,物件可以為null,所以不會產生問題。
4、@Basic
在預設情況下,Entity中屬笥載入方式都是即時載入(EAGER)的,當Enity物件例項化時,就加截了實體中相應的屬性值。
但對於一些特殊屬笥,比如大文字型text、位元組流型blob型的資料,在載入Entity時,這些屬性對應的資料量比較大,有時建立實體時如果也載入的話,可能造成資源嚴重佔用。那麼就可以為這些特殊的實體屬性設定載入方式為惰性載入(LAZY)
(1)fetch屬性表示獲取值的方式,它的值定義的列舉型,可選值為LAZY、EAGER。其中EAGER表示即時載入、LAZY表示惰性載入。預設為即時載入。
(2)optional表示屬性是否可以為null,不能用於java基本資料型( byte、int、short、long、boolean、char、float、double )。
如:
Java程式碼- @Basic(fetch=FetchType.LAZY)
- @Column(name = “contact_name”,columnDefinition=“ clob not null” )
- private String name;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
5、@Id
主鍵是實體的唯一標識,呼叫EntityManager的find方法,可以獲得相應的實體物件。每一個實體類至少要有一個主鍵(Primary key)。
一旦使用@Id 標記屬性為主鍵,該實體屬性的值可以指定,也可以根據一些特定的規則自動生成。這就涉及另一個標記@GeneratedValue 的使用。
@GeneratedValue 標註有以兩個屬性:
(1)strategy 屬性表示生成主鍵的策略 ,有4種類型,分別定義在列舉型GenerationType中,其中有GenerationType.TABLE 、 GenerationType.SEQUENCE 、 GenerationType.IDENTITY 、 GenerationType.AUTO ,其中,預設為AUTO,表示自動生成。
(2)generator 為不同策略型別所對應的生成規則名,它的值根據不同的策略有不同的設定。
(3)能夠標識為主鍵的屬性型別,有如表5-2所列舉的幾種。
分類 | 型別 |
Java的基本資料型別 | byte、int、short、long、char |
Java的基本資料型別對應的封裝類 | Byte、Integer、Short、Long、Character |
大數值型別 | java.math.BigInteger |
字串型別 | java.lang.String |
時間日期型 | java.util.Date java.sql.Date |
double和float浮點型別和它們對應的封裝類不能作為主鍵,這是因為判斷是否唯一是通過equals方法來判斷的,浮點型的精度太大,不能夠準確地匹配。
例一,自增主鍵 。在不同的資料庫,自增主鍵的生成策略可能有所不同。例如MySQL的自增主鍵可以通過IDENTITY來實現,而Oracle可能需要建立Sequence來實現自增。JPA的實現將會根據不同的資料庫型別來實現自增的策略。
Java程式碼- @Id
- @GeneratedValue(strategy = GenerationType.AUTO)
- public Long getId() {
- return id;
- }
- public void setId(Long id) {
- this.id = id;
- }
例二,表生成器 。將當前主鍵的值單獨儲存到一個數據庫的表中,主鍵的值每次都是從指定的表中查詢來獲得,這種生成主鍵的方式也是很常用的。這種方法生成主鍵的策略可以適用於任何的資料庫,不必擔心與同資料庫不相容造成問題。
配置的Customer類
- package model;
- import java.io.Serializable;
- import javax.persistence.Basic;
- import javax.persistence.Column;
- import javax.persistence.Entity;
- import javax.persistence.GeneratedValue;
- import javax.persistence.GenerationType;
- import javax.persistence.Id;
- import javax.persistence.Table;
- import javax.persistence.TableGenerator;
- @Entity
- @Table(schema = “open_jpa”, name = “customer”)
- public class Customer implements Serializable
- {
- private static final long serialVersionUID = -8480590552153589674L;
- private Integer id;
- private String name;
- @Id
- @GeneratedValue(strategy = GenerationType.TABLE, generator = “customer_gen”)
- @TableGenerator(schema = “open_jpa”,
- name = ”customer_gen”,
- table = ”tbl_generator”,
- pkColumnName = ”gen_name”,
- pkColumnValue = ”CUSTOMER_PK”,
- valueColumnName = ”gen_value”,
- allocationSize = 1,
- initialValue = 0)
- public Integer getId()
- {
- return id;
- }
- public void setId(Integer id)
- {
- this.id = id;
- }
- @Basic
- @Column(name = “name”)
- public String getName()
- {
- return name;
- }
- public void setName(String name)
- {
- this.name = name;
- }
- }
(1)在Entity標記的主鍵的位置,指定主鍵生成策略為“GenerationType.TABLE ”。
(2)指定生成主鍵策略的名稱,例如這裡命名為“generator = “customer_gen” ”。
(3)使用@TableGenerator標定義表生成策略的具體設定:
Java程式碼- @TableGenerator(schema = “open_jpa”,
- name = ”customer_gen”,
- table = ”tbl_generator”,
- pkColumnName = ”gen_name”,
- pkColumnValue = ”CUSTOMER_PK”,
- valueColumnName = ”gen_value”,
- allocationSize = 1,
- initialValue = 0)
可以看到資料生成tbl_generator 的結構及新增的資料:
Sql程式碼- CREATE TABLE `tbl_generator` (
- `GEN_NAME` varchar(255) NOT NULL,
- `GEN_VALUE` bigint(20) default NULL,
- PRIMARY KEY (`GEN_NAME`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- INSERT INTO tbl_generator VALUES (‘CUSTOMER_PK’, 1);
使用Oracle的sequence方式生成ID值。
Java程式碼- @Id
- @GeneratedValue(strategy = GenerationType.SEQUENCE,generator=“payablemoney_seq”)
- @SequenceGenerator(name=“payablemoney_seq”, sequenceName=“seq_payment”)
@SequenceGenerator定義
Java程式碼- @Target({TYPE, METHOD, FIELD})
- @Retention(RUNTIME)
- public @interface SequenceGenerator {
- String name();
- String sequenceName() default “”;
- int initialValue() default 0;
- int allocationSize() default 50;
- }
name屬性表示該表主鍵生成策略的名稱,它被引用在@GeneratedValue中設定的“generator”值中。
sequenceName屬性表示生成策略用到的資料庫序列名稱。
initialValue表示主鍵初識值,預設為0。
allocationSize表示每次主鍵值增加的大小,例如設定成1,則表示每次建立新記錄後自動加1,預設為50。