Hibernate的注解方法的使用


1、配置映射關系的xml方式

我們知道,Hibernate是一個典型的ORM框架,用以解決對象和關系的不匹配。其思想就是將關系數據庫中表的記錄映射成為對象,以對象形式展現,這樣一來,就可以把對數據庫的操作轉化為對對象的操作。

而ORM一般是采用xml的格式保存對象與關系數據表的映射,我們也可以從下面示例中看到hibernate中的一個映射配置表的表現形式:
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="com.zker.model.job.SysJob" table="SYS_JOB" lazy="true">
        <id name="jobId" column="JOB_ID">
            <generator class="sequence">
                <param name="sequence">SEQ_SYS_JOB</param>
            </generator>
        </id>
        <property name="jobName" type="string" column="JOB_NAME" />
        <property name="jobDesc" type="string" column="JOB_DESC" />
        <property name="lastModity" type="timestamp" column="LAST_MODIFY" />
        <!--與用戶關聯-->
        <set name="sysUsers" table="SYS_USER">
            <key column="JOB_ID" />
            <one-to-many class="com.zker.model.user.SysUser" />
        </set>

    </class>
</hibernate-mapping>

其中對應的實體類和數據庫表結構如下:
public class SysJob {
    /**職位的主鍵ID*/
    private int jobId;

    /**職位的名稱*/
    private String jobName;

    /**職位的描述*/
    private String jobDesc;

    /**職位的修改時間*/
    private Timestamp lastModity;

    /**職位所對應的用戶*/
    private Set<SysUser> sysUsers = new HashSet<SysUser>();

    public int getJobId() {
        return jobId;
    }

    public void setJobId(int jobId) {
        this.jobId = jobId;
    }

    public String getJobName() {
        return jobName;
    }

    public void setJobName(String jobName) {
        this.jobName = jobName;
    }

    public String getJobDesc() {
        return jobDesc;
    }

    public void setJobDesc(String jobDesc) {
        this.jobDesc = jobDesc;
    }

    public Timestamp getLastModity() {
        return lastModity;
    }

    public void setLastModity(Timestamp lastModity) {
        this.lastModity = lastModity;
    }

    public Set<SysUser> getSysUsers() {
        return sysUsers;
    }

    public void setSysUsers(Set<SysUser> sysUsers) {
        this.sysUsers = sysUsers;
    }
}
 

2、注解的優點


而完成這個ORM映射關系配置的方式,還有一種,就是使用注解。
  • 充分利用 Java 的反射機制獲取類結構信息,這些信息可以有效減少配置的工作
  • 注釋和 Java 代碼位於一個文件中,有助於增強程序的內聚性,便於程序員開發

我們可以看如下的一個示例來感受這種形式:

@Entity
@Table(name = "t_student")
@Domain(name = "學生")
@Generated
@DataIdentify(identifies = "number")
public class Student extends BaseDomain<Student> implements Addable, Modifiable<Student>, Deletable {
	private String name;
	private String number;
	private Sex sex;

	@Basic
	@NotSemanticNull(groups = {Groups.Add.class, Groups.Update.class})
	@Property(name = "姓名")
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

        ...

}


3、常用注解的使用方法

3.1 類級別的注解

  • @Entity     映射實體類
  • @Table      映射數句庫表

@Entity(name = "tableName") - 必須,注解將一個類聲明為一個實體bean,即指出該Java 類為實體類,將映射到指定的數據庫表
  • 屬性:
  • name - 可選,對應數據庫中的一個表。若表名與實體類名相同,則可以省略

@Table(name = "", catalog = "", schema = "")  - 可選,通常和@Entity 配合使用,只能標注在實體的 class 定義處,表示實體對應的數據庫表的信息
  • 屬性:
  • name - 可選,表示表的名稱,默認的表名和實體名稱一致,只有在不一致的情況下才需要指定表名
  • catalog - 可選,表示Catalog 名稱,默認為 Catalog("")
  • schema - 可選 , 表示 Schema 名稱 , 默認為Schema("")

3.2 屬性級別的注解

  • @Id                                 映射生成主鍵
  • @GeneratedValue         定義主鍵生成策略
  • @SequenceGenerator  聲明了一個數據庫序列
  • @Version                       定義樂觀鎖
  • @Basic                           聲明屬性的存取策略
  • @Column                       映射表的列
  • @Transient                    定義暫態屬性

屬性級別的注解,都是放在其對應的getter前。

3.2.1 與主鍵相關注解

@Id - 必須,定義了映射到數據庫表的主鍵的屬性,一個實體只能有一個屬性被映射為主鍵,置於 getXxx() 前

@GeneratedValue(strategy = GenerationType , generator="") - 可選,用於定義主鍵生成策略
  • 屬性:
  • strategy - 表示主鍵生成策略,取值有:
    • GenerationType.AUTO 根據底層數據庫自動選擇(默認),若數據庫支持自動增長類型,則為自動增長
    • GenerationType.INDENTITY 根據數據庫的Identity字段生成,支持DB2、MySQL、MS、SQL Server、SyBase與HyperanoicSQL數據庫的Identity類型主鍵
    • GenerationType.SEQUENCE 使用Sequence來決定主鍵的取值,適合Oracle、DB2等支持Sequence的數據庫,一般結合@SequenceGenerator使用(Oracle沒有自動增長類型,只能用Sequence)
    • GenerationType.TABLE  使用指定表來決定主鍵取值,結合@TableGenerator使用
  • generator - 表示主鍵生成器的名稱,這個屬性通常和ORM框架相關 , 例如:Hibernate 可以指定 uuid 等主鍵生成方式

@SequenceGenerator — 注解聲明了一個數據庫序列
  • 屬性:
  • name - 表示該表主鍵生成策略名稱,它被引用在@GeneratedValue中設置的“gernerator”值中
  • sequenceName - 表示生成策略用到的數據庫序列名稱
  • initialValue - 表示主鍵初始值,默認為0
  • allocationSize - 每次主鍵值增加的大小,例如設置成1,則表示每次創建新記錄后自動加1,默認為50


3.2.2 與非主鍵相關注解

@Version - 可以在實體bean中使用@Version注解,通過這種方式可添加對樂觀鎖定的支持(見參考鏈接)

@Basic - 用於聲明屬性的存取策略:
  • @Basic(fetch=FetchType.EAGER)   即時獲取(默認的存取策略)
  • @Basic(fetch=FetchType.LAZY)       延遲獲取

@Column - 可將屬性映射到列,使用該注解來覆蓋默認值,@Column描述了數據庫表中該字段的詳細定義
  • 屬性:
  • name - 可選,表示數據庫表中該字段的名稱,默認情形屬性名稱一致
  • nullable - 可選,表示該字段是否允許為 null,默認為 true
  • unique - 可選,表示該字段是否是唯一標識,默認為 false
  • length - 可選,表示該字段的大小,僅對 String 類型的字段有效,默認值255
  • insertable - 可選,表示在ORM框架執行插入操作時,該字段是否應出現INSETRT語句中,默認為 true
  • updateable - 可選,表示在ORM 框架執行更新操作時,該字段是否應該出現在UPDATE 語句中,默認為 true。對於一經創建就不可以更改的字段,該屬性非常有用,如對於 birthday 字段
  • columnDefinition - 可選,表示該字段在數據庫中的實際類型。通常ORM 框架可以根據屬性類型自動判斷數據庫中字段的類型,但是對於Date 類型仍無法確定數據庫中字段類型究竟是 DATE,TIME 還是 TIMESTAMP. 此外 ,String 的默認映射類型為 VARCHAR, 如果要將 String 類型映射到特定數據庫的 BLOB或 TEXT 字段類型,該屬性非常有用

@Transient - 可選,表示該屬性並非一個到數據庫表的字段的映射,ORM框架將忽略該屬性,如果一個屬性並非數據庫表的字段映射,就務必將其標示為@Transient,否則ORM框架默認其注解為 @Basic


3.3 映射實體類的關聯關系

單向一對多:一方有集合屬性,包含多個多方,而多方沒有一方的引用。 用戶--->電子郵件
單向多對一:多方有一方的引用,一方沒有多方的引用。 論文類別---> 類別
雙向一對多:兩邊都有多方的引用,方便查詢。 班級---> 學生
雙向多對一:兩邊都有多方的引用,方便查詢。
單向多對多:需要一個中間表來維護兩個實體表。 論壇--->文章
單向一對一:數據唯一,數據庫數據也是一對一。 艦船---> 水手
主鍵相同的一對一:使用同一個主鍵,省掉外鍵關聯。 客戶---> 地址

3.3.1 關聯映射的一些共有屬性

@JoinColumn - 可選,用於描述一個關聯的字段。 @JoinColumn和@Column類似,介量描述的不是一個簡單字段,而是一個關聯字段,例如描述一個 @ManyToOne 的字段。(即用來 定義外鍵在我們這個表中的屬性名,例如實體Order有一個User user屬性來關聯實體User,則Order的user屬性為一個外鍵
  • 屬性:
  • name - 該字段的名稱,由於@JoinColumn描述的是一個關聯字段,如ManyToOne, 則默認的名稱由其關聯的實體決定

@OneToOne@OneToMany@ManyToOneManyToMany 的共有屬性:
  • fetch - 配置加載方式。取值有:
    • Fetch.EAGER -  及時加載,多對一默認是Fetch.EAGER 
    • Fetch.LAZY - 延遲加載,一對多默認是Fetch.LAZY
  • cascade - 設置級聯方式,取值有:
    • CascadeType.PERSIST - 保存  - 調用JPA規范中的persist(),不適用於Hibernate的save()方法
    • CascadeType.REMOVE - 刪除  - 調用JPA規范中的remove()時,適用於Hibernate的delete()方法
    • CascadeType.MERGE - 修改  - 調用JPA規范中merge()時,不適用於Hibernate的update()方法 
    • CascadeType.REFRESH - 刷新  - 調用JPA規范中的refresh()時,適用於Hibernate的flush()方法
    • CascadeType.ALL - 全部  - JPA規范中的所有持久化方法
  • targetEntity - 配置集合屬性類型,如:@OneToMany(targetEntity=Book.class)

@OneToOne – 表示一個一對一的映射
主表類A與從表類B的主鍵值相對應
主表:
@OneToOne(cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn
public B getB(){
  return b;
}

從表:無   
主表A中有一個從表屬性是B類型的b
主表:
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name="主表外鍵")   //這里指定的是數據庫中的外鍵字段。
public B getB(){
  return b;
}

從表:無
主表A中有一個從表屬性是B類型的b,同時,從表B中有一個主表屬性是A類型的a
主表:
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name="主表外鍵")   //這里指定的是數據庫中的外鍵字段。
public B getB(){
  return b;
}

從表:
@OneToOne(mappedBy = "主表類中的從表屬性")
public 主表類 get主表類(){
  return 主表對象
}

@ManyToOne - 表示一個多對一的映射,該注解標注的屬性通常是數據庫表的外鍵
單向多對一:多方有一方的引用,一方沒有多方的引用
在多方
@ManyToOne(targetEntity=XXXX.class)   //指定關聯對象
@JoinColumn(name="")                 //指定產生的外鍵字段名
雙向多對一:配置方式同雙向一對多
// 示例
// 訂單 Order 和用戶 User 是一個 ManyToOne 的關系
// 在 Order 類中定義
@ManyToOne()
@JoinColumn(name="USER")
public User getUser() {
  return user;
}

@OneToMany - 描述一個一對多的關聯,該屬性應該為集合類型,在數據庫中並沒有實際字段
單向一對多:一方有集合屬性,包含多個多方,而多方沒有一方的引用
@OneToMany  默認會使用連接表做一對多關聯
添加@JoinColumn(name="xxx_id") 后,就會使用外鍵關聯,而不使用連接表了
雙向一對多:
1)在多方
@ManyToOne
@JoinColumn(name="自己的數據庫外鍵列名")
 
2)在一方
@OneToMany(mappedBy="多端的關聯屬性名") //mappedBy相當於inverse,維護外鍵的控制權,不能和JoinColumn同時使用
@JoinColumn(name="對方的數據庫外鍵列名")
注意:對於外鍵的維護,如果是雙向一對多,希望雙方均可以維護外鍵,則不能使用mappedBy,而應該雙方都使用@JoinColumn

@ManyToMany - 可選,描述一個多對多的關聯
  • 屬性:
  • targetEntity - 表示多對多關聯的另一個實體類的全名,例如:package.Book.class
  • mappedBy - 用在雙向關聯中,把關系的維護權翻轉。    
單向多對多關聯:
在主控方加入@ManyToMany注解即可。
雙向多對多關聯:
兩個實體間互相關聯的屬性必須標記為@ManyToMany,並相互指定targetEntity屬性。
有且只有一個實體的@ManyToMany注解需要指定mappedBy屬性,指向targetEntity的集合屬性名稱。

3.3.2 關聯映射的其他補充

@JoinTable其實同時也是配合 @ManyToMany使用的, @ManyToMany注釋表示該對象是多對多關系的一端,然后利用@JoinTable來定義關聯關系(利用中間表來建立聯系, 原因戳這里),其中name屬性指定中間表名稱,j oinColumns定義中間表與該表的外鍵關系,inverseJoinColumns屬性定義了中間表與另外一端的外鍵關系。

@JoinTable - 定義關聯表, 該關聯表包含了指回實體表的外鍵(通過@JoinTable.joinColumns) 以及指向目標實體表的外鍵(通過@JoinTable.inverseJoinColumns)

e.g.
如下表示:該屬性對應字段為"resource_type",該字段實際在另外一張名"r_role_x_resource_type"表中,與該表("p_role")通過"role_id"進行外鍵鏈接

(class Role --> table "p_role")
@ElementCollection
@JoinTable(name = "r_role_x_resource_type", joinColumns = @JoinColumn(name = "role_id"))
@Column(name = "resource_type")
@JSONField(serialize = false)
@Cache(usage = CacheConcurrencyStrategy.NONE)
public List<Class<? extends Resourceable>> getResourceTypeList() {
	return resourceTypeList;
}

e.g.
如下表示:關聯的表為“r_role_x_permission",其中關聯外鍵為"role_id",該表又通過"permission_id"鏈接第三張表,即目標實體表

(class Role --> table "p_role")
@ManyToMany
@JoinTable(name = "r_role_x_permission", joinColumns = @JoinColumn(name = "role_id"),
	inverseJoinColumns = @JoinColumn(name = "permission_id"))
public List<Permission> getPermissionList() {
	return permissionList;
}



4、其他注解

@DiscriminatorValue - 一張表對應一整棵類繼承樹時,該類別對應的“表part”

首先參考這篇文章,很重要: hibernate映射繼承關系(一):一張表對應一整棵類繼承樹,從文中可以知道,用一個表來存儲對應的整個類別的數據,比如有Cat和Animal,Cat是Animal的子類,我僅用Animal一個表來存儲Animal和Cat的字段和數據,而不是分成兩個表。那么當我進行映射關系的時候,假如我要Cat類映射到Animal中Cat的部分,如何處理?在Animal中定義一個字段用來區分不同的表,比如Animal表中我額外增加字段名為Type,那么在Animal這一張表中,我們本屬於Animal表內容的,該字段我們設置為animal,本屬於Cat表的,該字段我們設置為cat。你可以理解為,新增加字段來用以在同一個表中區分不同類別的內容。

所以對應在注解上的使用的一個映射關系表示,就是這樣的:對於”父類“,即准備用來囊括所有內容的那個表,我們需要定義這個對應的類為 @DiscriminatorColumn(name = "xxx", discriminatorType = DiscriminatorType.xxx) ,這里的 name就是指定表中用來區別各類內容的字段 ,而對於”子類“,我們需要注解標明@DiscriminatorValue(xxx),這里的xxx即對應了父類中的 “區別用字段” 里的標識。

舉例來說,就是假如我們希望將Animal和Cat的內容都只存儲在Animal這張表里,那么為了區分內容,我們對於Animal這個表新增某字段如 type;Animal的類,注解為@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING) ,同時設置@DiscriminatorValue("animal");Cat extends Animal,Cat的類,注解為@DiscriminatorValue(“cat");那么Animal這個表中,字段type中,為animal的元組映射Animal類,為cat的元組映射Cat類。

而這種方式,多用於數據庫字典概念。

@Transient
如果某個屬性不需要被持久化,可以加上 @javax.persistence.Transient 注解或者使用 java 的 transient 關鍵字。

@Lob
實體BLOB、CLOB類型的注解:
  • BLOB類型屬性聲明為byte[]或者java.sql.Blob,多用來直接將文件存儲在數據庫字段中(如圖片);
  • CLOB類型的屬性聲明為String或java.sql.Clob (詳可見參考鏈接中《Hibernate的Annotation實體BLOB、CLOB類型注解》)


5、參考鏈接




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM