最近學習hibernate注解形式配置POJO類,將注解的解析記下來,以備以后使用。
例1.
@Entity
@Table(name="user")
public class Flight implements Serializable {
Long id;
@Id
@GeneratedValue(generator="generator")
@GenericGenerator(name="generator", strategy = "native")
public Long getId() { return id; }
public void setId(Long id)
{ this.id = id; }
}
Hibernate 可以對類的屬性或者方法進行注解。屬性對應field類別,方法的 getXxx()對應property類別。
@Entity
聲明一個類為實體Bean。
@Table
說明此實體類映射的表名,目錄,schema的名字。
@Id
聲明此表的主鍵。
@GeneratedValue
定義主鍵的增長策略。我這里一般交給底層數據庫處理,所以調用了名叫generator的增長方式,由下邊的@GenericGenerator實現
@GenericGenerator
hibernate內部的主鍵增長方式.
關于@GeneratedValue和@GenericGenerator的詳細說明,在我的另一篇轉載的文章里邊有。
@GeneratedValue 與 @GenericGenerator
例2.
@Table(name="tbl_sky",
uniqueConstraints = {@UniqueConstraint(columnNames={"month", "day"})} )
@UniqueConstraint
將對應的字段設置唯一性標識
(注:UniqueConstraint只在hibernate.hbm2ddl.auto設置為create-drop才會起作用)
例3.
1 public class Flight implements Serializable {
2 @Version
3 @Column(name="OPTLOCK")
4 public Integer getVersion() {} }
@Version
注解用于支持樂觀鎖版本控制。一般可以用 數字 或者 timestamp 類型來支持 version.
@Column
用于映射對應的字段,其中參數詳解如下:
name = "columnName"; (1)
boolean unique() default false; (2)
boolean nullable() default true; (3)
boolean insertable() default true; (4)
boolean updatable() default true; (5)
String columnDefinition() default ""; (6)
String table() default ""; (7)
int length() default 255; (8)
int precision() default 0; (9)
int scale() default 0; (10)
(1) name 可選,列名(默認值是屬性名)
(2) unique 可選,是否在該列上設置唯一約束(默認值false)
(3) nullable 可選,是否設置該列的值可以為空(默認值true)
(4) insertable 可選,該列是否作為生成的insert語句中的一個列(默認值true)
(5) updatable 可選,該列是否作為生成的update語句中的一個列(默認值true)
(6) columnDefinition 可選,為這個特定列覆蓋SQL DDL片段 (這可能導致無法在不同數據庫間移植)
(7) table 可選,定義對應的表(默認為主表)
(8) length 可選,列長度(默認值255)
(9) precision 可選,列十進制精度(decimal precision)(默認值0)
(10) scale 可選,如果列十進制數值范圍(decimal scale)可用,在此設置(默認值0)
例4.
public class user
{
@Transient
private Integer id;
@Basic(fetch=FetchType.LAZY,optional=true)
private String name;
@Transient
public Integer getId() {}
@Temporal(TemporalType.TIME)
public java.util.Date getDatetime() {};
}
@Transient
被注解成 @Transient 的 getter 方法或屬性,將不會被持久化(自己測試,只有放在getter方法內才起作用)
@Basic
所有沒有定義注解的屬性,等價于在其上面添加了 @Basic注解可以聲明屬性的獲取策略 ( fetch strategy ): fetch:抓取策略,延時加載與立即加載,optional:指定在生成數據庫結構時字段是否允許為 null.
@Temporal
在核心的 Java API 中并沒有定義時間精度 ( temporal precision )。因此處理時間類型數據時,你還需要定義將其存儲在數據庫中所預期的精度。
在數據庫中,表示時間類型的數據有 DATE,TIME,和 TIMESTAMP 三種精度 ( 即單純的日期,時間,或者兩者兼備 )。 可使用 @Temporal 注解來調整精度。
映射實體Bean的關聯關系
一對一
使用 @OneToOne 注解可以建立實體Bean之間的一對一關系。一對一關系有3種情況。
? 關聯的實體都共享同樣的主鍵。
@Entity
public class Body {
@Id
public Long getId() { return id; }
@OneToOne(cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn
public Heart getHeart() {
return heart;
}
...
}
@Entity
public class Heart {
@Id
public Long getId() { ...}
}
通過@PrimaryKeyJoinColumn 注解定義了一對一的關聯關系。
? 其中一個實體通過外鍵關聯到另一個實體的主鍵。注:一對一,則外鍵必須為唯一約束。
@Entity
public class Customer implements Serializable {
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name="passport_fk")
public Passport getPassport() {
...
}
@Entity
public class Passport implements Serializable {
@OneToOne(mappedBy = "passport")
public Customer getOwner() {
...
}
通過@JoinColumn注解定義一對一的關聯關系。如果沒有@JoinColumn注解,則系統自動處理,在主表中將創建連接列,列名為:主題的關聯屬性名 + 下劃線 + 被關聯端的主鍵列名。上例為 passport_id, 因為Customer 中關聯屬性為 passport, Passport 的主鍵為 id.
? 通過關聯表來保存兩個實體之間的關聯關系。注:一對一,則關聯表每個外鍵都必須是唯一約束。
@Entity
public class Customer implements Serializable {
@OneToOne(cascade = CascadeType.ALL)
@JoinTable(name = "CustomerPassports",
joinColumns = @JoinColumn(name="customer_fk"),
inverseJoinColumns = @JoinColumn(name="passport_fk")
)
public Passport getPassport() {
...
}
@Entity public class Passport implements Serializable {
@OneToOne(mappedBy = "passport")
public Customer getOwner() {
...
}
Customer 通過 CustomerPassports 關聯表和 Passport 關聯。該關聯表通過 passport_fk 外鍵指向 Passport 表,該信心定義為 inverseJoinColumns 的屬性值。 通過 customer_fk 外鍵指向 Customer 表,該信息定義為 joinColumns 屬性值。
多對一
使用 @ManyToOne 注解定義多對一關系。
@Entity()
public class Flight implements Serializable {
@ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
@JoinColumn(name="COMP_ID")
public Company getCompany() {
return company;
}
...
}
其中@JoinColumn 注解是可選的,關鍵字段默認值和一對一關聯的情況相似。列名為:主題的關聯屬性名 + 下劃線 + 被關聯端的主鍵列名。本例中為company_id,因為關聯的屬性是company, Company的主鍵為 id.
@ManyToOne 注解有個targetEntity屬性,該參數定義了目標實體名。通常不需要定義,大部分情況為默認值。但下面這種情況則需要 targetEntity 定義(使用接口作為返回值,而不是常用的實體)。
@Entity()
public class Flight implements Serializable {
@ManyToOne(cascade= {CascadeType.PERSIST,CascadeType.MERGE},targetEntity= CompanyImpl.class)
@JoinColumn(name="COMP_ID")
public Company getCompany() {
return company;
}
...
}
public interface Company {
...
多對一也可以通過關聯表的方式來映射,通過@JoinTable 注解可定義關聯表。該關聯表包含指回實體的外鍵(通過@JoinTable.joinColumns)以及指向目標實體表的外鍵(通過@JoinTable.inverseJoinColumns).
@Entity()
public class Flight implements Serializable {
@ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
@JoinTable(name="Flight_Company",
joinColumns = @JoinColumn(name="FLIGHT_ID"),
inverseJoinColumns = @JoinColumn(name="COMP_ID")
)
public Company getCompany() {
return company;
}
...
}
非主鍵多對一關聯:
A表:sn B表:cp_sn
A表配置:
1 private List<B> sns;
2
3 @OneToMany(mappedBy = "a", fetch = FetchType.LAZY)
4 public List<B> getSns() {
5 return sns;
6 }
7
8 public void setSns(List<B> sns) {
9 this.sns = sns;
10 }
B表配置:
1 private A a;
2
3 @ManyToOne(fetch = FetchType.LAZY)
4 @JoinColumn(name = "CP_SN", referencedColumnName="sn", insertable = false, updatable = false)
5 public A getA() {
6 return a;
7 }
name = "CP_SN" -- 本表中的字段
referencedColumnName="sn" -- 關聯表的字段
集合類型
一對多
@OneToMany 注解可定義一對多關聯。一對多關聯可以是雙向的。
雙向
規范中多對一端幾乎總是雙向關聯中的主體(owner)端,而一對多的關聯注解為 @OneToMany(mappedBy=)
@Entity
public class Troop {
@OneToMany(mappedBy="troop")
public Set<Soldier> getSoldiers() {
...
}
@Entity
public class Soldier {
@ManyToOne
@JoinColumn(name="troop_fk")
public Troop getTroop() {
...
}
Troop 通過troop屬性和Soldier建立了一對多的雙向關聯。在 mappedBy 端不必也不能定義任何物理映射。
單向
@Entity
public class Customer implements Serializable {
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@JoinColumn(name="CUST_ID")
public Set<Ticket> getTickets() {
...
}
@Entity
public class Ticket implements Serializable {
... //no bidir
}
一般通過連接表來實現這種關聯,可以通過@JoinColumn注解來描述這種單向關聯關系。上例 Customer 通過 CUST_ID 列和 Ticket 建立了單向關聯關系。
通過關聯表來處理單向關聯
@Entity
public class Trainer {
@OneToMany
@JoinTable(
name="TrainedMonkeys",
joinColumns = @JoinColumn( name="trainer_id"),
inverseJoinColumns = @JoinColumn( name="monkey_id")
)
public Set<Monkey> getTrainedMonkeys() {
...
}
@Entity
public class Monkey {
... //no bidir
}
通過關聯表來處理單向一對多關系是首選,這種關聯通過 @JoinTable 注解來進行描述。上例子中 Trainer 通過TrainedMonkeys表和Monkey建立了單向關聯關系。其中外鍵trainer_id關聯到Trainer(joinColumns)而外鍵monkey_id關聯到Monkey(inverseJoinColumns).
默認處理機制
通過連接表來建立單向一對多關聯不需要描述任何物理映射,表名由一下3個部分組成,主表(owner table)表名 + 下劃線 + 從表(the other side table)表名。指向主表的外鍵名:主表表名+下劃線+主表主鍵列名 指向從表的外鍵定義為唯一約束,用來表示一對多的關聯關系。
@Entity
public class Trainer {
@OneToMany
public Set<Tiger> getTrainedTigers() {
...
}
@Entity
public class Tiger {
... //no bidir
}
上述例子中 Trainer 和 Tiger 通過 Trainer_Tiger 連接表建立單向關聯關系。其中外鍵 trainer_id 關聯到 Trainer表,而外鍵 trainedTigers_id 關聯到 Tiger 表。
多對多
通過@ManyToMany 注解定義多對多關系,同時通過 @JoinTable 注解描述關聯表和關聯條件。其中一端定義為 owner, 另一段定義為 inverse(對關聯表進行更新操作,這段被忽略)。
// 維護端注解
@ManyToMany (cascade = CascadeType.REFRESH)
@JoinTable (//關聯表
name = "student_teacher" , //關聯表名
inverseJoinColumns = @JoinColumn (name = "teacher_id" ),//被維護端外鍵
joinColumns = @JoinColumn (name = "student_id" ))//維護端外鍵被維護端注解
@ManyToMany(cascade = CascadeType.REFRESH,
mappedBy = "teachers",//通過維護端的屬性關聯
fetch = FetchType.LAZY)
// 關系維護端刪除時,如果中間表存在些紀錄的關聯信息,則會刪除該關聯信息;
// 關系被維護端刪除時,如果中間表存在些紀錄的關聯信息,則會刪除失敗 .
默認值:
關聯表名:主表表名 + 下劃線 + 從表表名;關聯表到主表的外鍵:主表表名 + 下劃線 + 主表中主鍵列名;關聯表到從表的外鍵名:主表中用于關聯的屬性名+ 下劃線 + 從表的主鍵列名。
用 cascading 實現傳播持久化(Transitive persistence)
cascade 屬性接受值為 CascadeType 數組,其類型如下:
? CascadeType.PERSIST: cascades the persist (create) operation to associated entities persist() is called or if the entity is managed 如果一個實體是受管狀態,或者當 persist() 函數被調用時,觸發級聯創建(create)操作。
? CascadeType.MERGE: cascades the merge operation to associated entities if merge() is called or if the entity is managed 如果一個實體是受管狀態,或者當 merge() 函數被調用時,觸發級聯合并(merge)操作。
? CascadeType.REMOVE: cascades the remove operation to associated entities if delete() is called 當 delete() 函數被調用時,觸發級聯刪除(remove)操作。
? CascadeType.REFRESH: cascades the refresh operation to associated entities if refresh() is called 當 refresh() 函數被調用時,出發級聯更新(refresh)操作。
? CascadeType.ALL: all of the above 以上全部
其他屬性:
@Enumerated
@javax.persistence.Enumerated(EnumType.STRING)
value:EnumType.STRING,EnumType.ORDINAL
枚舉類型成員屬性映射,EnumType.STRING指定屬性映射為字符串,EnumType.ORDINAL指定屬性映射為數據序
@Lob
@javax.persistence.Lob
用于標注字段類型為Clob和Blob類型
Clob(Character Large Ojects)類型是長字符串類型,實體的類型可為char[]、Character[]、或者String類型
Blob(Binary Large Objects)類型是字節類型,實體的類型可為byte[]、Byte[]、或者實現了Serializable接口的類。
通常使用惰性加載的方式, @Basic(fetch=FetchType.LAZY)
@SecondaryTable
@javax.persistence.SecondaryTable
將一個實體映射到多個數據庫表中
如:
@Entity
@SecondaryTables({
@SecondaryTable(name = "Address"),
@SecondaryTable(name = "Comments")
})
public class Forum implements Serializable {
@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")
}
table屬性的值指定字段存儲的表名稱 沒有用 @Column 注解改變屬性默認的字段將會存在于 Forum 表
@Index
給某一字段加索引
例:
@Table(name = "tab_developer", indexes = {@Index(columnList = "username")})
根據注解,將會給username字段加上索引。