常用注解有下面這些:
①:@Entity、@Table、@Id、@GeneratedValue、@Column、@Basic
②:@Transient 用於忽略某個屬性,而不對該屬性進行持久化操作
③:@Temporal
一、第①組注解
- @Entity 標注用於實體類聲明語句之前,指出該Java 類為實體類,將映射到指定的數據庫表。如聲明一個實體類 Customer,它將映射到數據庫中的 customer 表上。
-
@Table,當實體類與其映射的數據庫表名不同名時需要使用 @Table 標注說明,該標注與 @Entity 標注並列使用,置於實體類聲明語句之前,可寫於單獨語句行,也可與聲明語句同行。 @Table 標注的常用選項是 name,用於指明數據庫的表名。
-
@Id 標注用於聲明一個實體類的屬性映射為數據庫的主鍵列。該屬性通常置於屬性聲明語句之前,可與聲明語句同行,也可寫在單獨行上。 @Id標注也可置於屬性的getter方法之前。
- @GeneratedValue 用於標注主鍵的生成策略,通過 strategy 屬性指定。默認情況下,JPA 自動選擇一個最適合底層數據庫的主鍵生成策略:SqlServer 對應 identity,MySQL 對應 auto increment。
在 javax.persistence.GenerationType 中定義了以下幾種可供選擇的策略:
—— IDENTITY:采用數據庫 ID自增長的方式來自增主鍵字段,Oracle 不支持這種方式;
—— AUTO: JPA自動選擇合適的策略,是默認選項;
—— SEQUENCE:通過序列產生主鍵,通過 @SequenceGenerator 注解指定序列名,MySql 不支持這種方式
—— TABLE:通過表產生主鍵,框架借由表模擬序列產生主鍵,使用該策略可以使應用更易於數據庫移植(TABLE生成主鍵將會在后面詳細講解)。
- @Basic 表示一個簡單的屬性到數據庫表的字段的映射,對於沒有任何標注的 getXxxx() 方法,默認即為@Basic
—— fetch: 表示該屬性的讀取策略,有 EAGER 和 LAZY 兩種,分別表示主支抓取和延遲加載,默認為 EAGER.
—— optional: 表示該屬性是否允許為null, 默認為true
-
@Column,當實體的屬性與其映射的數據庫表的列不同名時需要使用此注解說明,該屬性通常置於實體的屬性聲明語句之前,還可與 @Id 標注一起使用。
—— name 屬性,用於設置映射數據庫表的列名。此外,該標注還包含其它多個屬性,如:unique 、nullable、length 等。
—— columnDefinition 屬性: 表示該字段在數據庫中的實際類型。
a、通常 ORM 框架可以根據屬性類型自動判斷數據庫中字段的類型,但是對於Date類型仍無法確定數據庫中字段類型究竟是DATE,TIME還是TIMESTAMP。
b、此外,String的默認映射類型為VARCHAR, 如果要將 String 類型映射到特定數據庫的 BLOB 或TEXT 字段類型。
—— @Column 標注也可置於屬性的getter方法之前
二、第②組注解
- 表示該屬性並非一個到數據庫表的字段的映射,ORM框架將忽略該屬性。其作用類似於序列化中的@Transient注解。
- 如果一個屬性並非數據庫表的字段映射,就務必將其標示為@Transient;否則,ORM框架默認其注解為@Basic
三、第③組注解
-
在核心的 Java API 中並沒有定義 Date 類型的精度(temporal precision)。而在數據庫中,表示 Date 類型的數據有 DATE, TIME, 和 TIMESTAMP 三種精度(即單純的日期,時間,或者兩者 兼備). 在進行屬性映射時可使用@Temporal注解來調整精度。
四、接下來就是修改 2、JPA的HelloWorld 中的實體類Customer.java,將上面的注解都使用一遍,看看實際的效果:
1 package com.magicode.jpa.helloworld; 2 3 import java.util.Date; 4 5 import javax.persistence.Column; 6 import javax.persistence.Entity; 7 import javax.persistence.GeneratedValue; 8 import javax.persistence.GenerationType; 9 import javax.persistence.Id; 10 import javax.persistence.Table; 11 import javax.persistence.Temporal; 12 import javax.persistence.TemporalType; 13 import javax.persistence.Transient; 14 15 /** 16 * @Entity 用於注明該類是一個實體類 17 * @Table(name="t_customer") 表明該實體類映射到數據庫的 t_customer 表 18 */ 19 @Table(name="t_customer") 20 @Entity 21 public class Customer { 22 23 private Integer id; 24 private String lastName; 25 26 private String email; 27 private int age; 28 29 private Date birthday; 30 31 private Date createdTime; 32 33 /** 34 * @GeneratedValue(strategy=GenerationType.AUTO) 指明主鍵生成策略為AUTO 35 * @Id 表明實體類的主鍵 36 */ 37 @GeneratedValue(strategy=GenerationType.AUTO) 38 @Id 39 public Integer getId() { 40 return id; 41 } 42 43 /** 44 * @Column 指明lastName屬性映射到表的 LAST_NAME 列中 45 * 同時還可以指定其長度、能否為null等數據限定條件 46 */ 47 @Column(name="LAST_NAME", length=50, nullable=false) 48 public String getLastName() { 49 return lastName; 50 } 51 52 /** 53 * 利用 @Temporal 來限定birthday為DATE型 54 */ 55 @Column(name="birthday") 56 @Temporal(TemporalType.DATE) 57 public Date getBirthday() { 58 return birthday; 59 } 60 61 /* 62 * 通過 @Column 的 columnDefinition 屬性將CREATED_TIME列 63 * 映射為“DATE”類型 64 */ 65 @Column(name="CREATED_TIME", columnDefinition="DATE") 66 public Date getCreatedTime() { 67 return createdTime; 68 } 69 70 /* 71 * 通過 @Column 的 columnDefinition 屬性將email列 72 * 映射為“TEXT”類型 73 */ 74 @Column(columnDefinition="TEXT") 75 public String getEmail() { 76 return email; 77 } 78 79 /* 80 * 工具方法,不需要映射為數據表的一列 81 */ 82 @Transient 83 public String getInfo(){ 84 return "lastName: " + lastName + " email: " + email; 85 } 86 87 public int getAge() { 88 return age; 89 } 90 91 public void setId(Integer id) { 92 this.id = id; 93 } 94 95 public void setLastName(String lastName) { 96 this.lastName = lastName; 97 } 98 99 public void setEmail(String email) { 100 this.email = email; 101 } 102 103 public void setAge(int age) { 104 this.age = age; 105 } 106 107 public void setBirthday(Date birthday) { 108 this.birthday = birthday; 109 } 110 111 public void setCreatedTime(Date createdTime) { 112 this.createdTime = createdTime; 113 } 114 115 }
在main方法中的測試不變,只是在持久化customer的時候添加兩行代碼:
// 4、調用EntityManager的persist方法完成持久化過程 Customer customer = new Customer(); customer.setAge(9); customer.setEmail("Tom@163.com"); customer.setLastName("Tom"); //添加1 customer.setBirthday(new Date()); //添加2 customer.setCreatedTime(new Date()); em.persist(customer);
對Customer.java做如下幾點說明總結:
①、對getInfo()方法作為一個工具方法,不需要映射到數據庫中。所以,使用了@Transient,表示在持久化的時候忽略它。否則,JPA會默認getInfo方法使用了默認的@Basic注解,而將其持久化到數據庫的info列中。
②、getBirthday()方法上使用了@Temporal(TemporalType.DATE)注解,表明在持久化過程中將birthday對應的數據存為DATE(即只有“年月日”)。
同樣的效果體現在getCreatedTime方法上。雖然該方法沒有使用@Temporal注解,但是@Column(name="CREATED_TIME", columnDefinition="DATE")
指明了“映射數據庫列名為CREATED_TIME”、“對應列的數據類型為DATE型”
③、在getEmail()方法上使用了@Column(columnDefinition="TEXT"),指明email這一列的數據類型為“TEXT”(在存放大文本的時候使用)
④、從②和③可以看出,columnDefinition的取值就可以直接使用數據庫原生的類型名字即可
⑤、如果沒有使用@Column的name屬性指定映射的列名,那么默認的命名方法為getter規則:getXxx對應的名字為xxx(也就是第一個字母變小寫得到)
運行main方法以后建立的數據庫如下:
再看看表的結構: