SpringDataJPA在Entity中常用的注解淺析


  首先我們常用的注解包括(@Entity、@Table、@Id、@IdClass、@GeneratedValue、@Basic、@Transient、@Column、@Temporal、@Enumerated、@Lob)

  1. @Entity使用此注解定義的對象將會成為被JPA管理的實體,將映射到指定的數據庫表@Entity(name = "user")其中name默認是此實體類的名字,全局唯一。
  2.   @Table指定此實體類對應的數據庫的表名。若注解不加名字則系統認為表名和實體類的名字相同
  3.  @Id定義字段為數據庫的主鍵,一個實體里面必須有一個。

  4.  @IdClass利用外部類的聯合主鍵,其中外部類必須滿足一下幾點要求
    • 必須實現Serializable接口。
    • 必須有默認的public無參數的構造方法。

    • 必須覆蓋equals和hashCode方法。equals方法用於判斷兩個對象是否相同,EntityManger通過find方法來查找Entity時是根據equals的返回值來判斷的。hashCode方法返回當前對象的哈希碼,生成的hashCode相同的概率越小越好,算法可以進行優化。

  5.   @GeneratedValue為主鍵生成策略

    • 默認為AUTO即JPA自動選擇合適的策略

    • IDENTITY 適用於MySQL,策略為自增
    • SEQUENCE 通過序列生成主鍵通過@SquenceGenerator指定序列名MySQL不支持
    • TABLE 框架由表模擬產生主鍵,使用該策略有利於數據庫移植
  6.  @Basic表示此字段是映射到數據庫,如果實體字段上沒有任何注解默認為@Basic。其中可選參數為@Basic(fetch = FetchType.LAZY, optional = false)其中fetch默認為EAGER立即加載,LAZY為延遲加載、optional表示該字段是否可以為null
  7.  @Transient和@Basic的作用相反,表示該字段不是一個到數據庫表的字段映射,JPA映射數據庫的時候忽略此字段。
  8.  @Column定義實體內字段對應的數據庫中的列名
    @Column(name = "real_name", unique = true, nullable = false, insertable = false, updatable = false, columnDefinition = "varchar", length = 100)
    • name對應數據庫的字段名,可選默認字段名和實體屬性名一樣
    • unique是否唯一,默認false,可選
    • nullable是否允許為空。可選,默認為true
    • insertable執行insert的時候是否包含此字段。可選,默認true
    • updatable執行update的時候是否包含此字段。可選,默認true
    • columnDefinition表示該字段在數據庫中的實際類型
    • length數據庫字段的長度,可選,默認25
  9.  @Temporal用來設置Date類型的屬性映射到對應精度的字段

    @Temporal(TemporalType.DATE)    //映射為只有日期
    @Temporal(TemporalType.TIME)    //映射為只有時間
    @Temporal(TemporalType.TIMESTAMP)  //映射為日期+時間
  10. @Lob將字段映射成數據庫支持的大對象類型,支持一下兩種數據庫類型的字段。(注意:Clob、Blob占用的內存空間較大,一般配合@Basic(fetch = FetchType.LAZY)將其設置為延遲加載)

    • Clob:字段類型為Character[]、char[]、String將被映射為Clob
    • Blob:字段類型為Byte[]、byte[]和實現了Serializable接口的類型將被映射為Blob類型

  接下來介紹關聯關系注解(@JoinColumn、@OneToOne、@OneToMany、@ManyToOne、@ManyToMany、@JoinTable、@OrderBy)

  1. @JoinColumn定義外鍵關聯字段名稱,其中屬性意義如下
    • name表示目標表的字段名,必填

    • referencedColumnName本實體表的字段名,非必填,默認是本表的ID

    • unique外鍵字段是否唯一,可選,默認false
    • nullable外鍵字段是否允許為空,可選,默認true
    • insertable新增操作的時候是否跟隨一起新增,可選,默認true
    • updatable更新時候是否一起更新。可選,默認true

    @JoinColumn主要配合@OneToOne、@ManyToOne、@OneToMany一起使用,單獨使用沒有任何意義。

    @JoinColumns定義多個字段的關聯關系

  2. @OneToOne一對一關聯關系

@OneToOne(targetEntity = SysRole.class, cascade = {CascadeType.PERSIST,CascadeType.REMOVE,CascadeType.REFRESH,CascadeType.MERGE},fetch = FetchType.LAZY,optional = false,mappedBy = "userId",orphanRemoval = true)
    • targetEntity非必填,默認為該字段的類型
    • cascade級聯操作策略CascadeType.PERSIST級聯新建,CascadeType.REMOVE級聯刪除,CascadeType.REFRESH級聯刷新,CascadeType.MERGE級聯更新,CascadeType.ALL四項全選
    • fetch數據加載方式,默認EAGER(立即加載),LAZY(延遲加載)
    • optional是否允許為空。可選,默認為true
    • mappedBy關聯關系被誰維護,非必填,一般不需要特別指定。注意:只有關系維護方才能操作兩者的關系,被維護方即使設置了維護方的屬性進行存儲也不會更新外鍵關聯。mappedBy不能與@JoinColumn或者@JoinTable同時使用。mappedBy的值指的是另一方的實體里面屬性的字段,而不是數據庫字段,也不是實體對象的名字,即另一方配置了@JoinColumn或者@JoinTable注解的屬性的字段名稱
    • orphanRemoval是否級聯刪除,和CascadeType.REMOVE效果一樣,兩種只要配置一種就會自動級聯刪除

  @OneToOne需要配合@JoinColumn一起使用,可以雙向關聯,也可以只配置一方。下面我們舉一個例子:假設一個用戶只擁有一個角色SysUser如下

@OneToOne
@JoinColumn(name = "role_id",referencedColumnName = "user_id")
private SysRole role;
//若需要雙向關聯則SysRole的內容如下
@OneToOne(mappedBy = "role")
private SysUser user;
//當然也可以不用選擇mappedBy,使用下面效果也一樣
@OneToOne
@JoinColumn(name = "user_id",referencedColumnName = "role_id")
private SysUser user;

  3.@OneToMany@ManyToOne一對多和多對一的關聯關系

@Entity
@Table(name="user")
class User implements Serializable{
    private Long userId;
    @OneToMany(cascade = CascadeType.ALL,fetch = FetchType.LAZY,mappedBy = "user")
    private Set<Role> setRole;
}

@Entity
@Table(name="role")
class Role{
    private Long roleId;
    @ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
    @JoinColumn(name = "user_id")//user_id字段作為外鍵
    private User user;
}

  4.@OrderBy關聯查詢的時候排序,一般和@OneToMany一起使用

@Entity
@Table(name="user")
class User implements Serializable{
    private Long userId;
    @OneToMany(cascade = CascadeType.ALL,fetch = FetchType.LAZY,mappedBy = "user")
    @OrderBy("role_name DESC")
    private Set<Role> setRole;
}

  5.@JoinTable關聯關系表一般和@ManyToMany一起使用,@ManyToMany表示多對多,也有單雙向之分,單雙向和注解無關,只看實體類之間是否相互引用

@JoinTable(name = "sys_user_role",
        joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
        inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "id")})
@ManyToMany(cascade = {CascadeType.REFRESH}, fetch = FetchType.EAGER)
private List<SysRole> roles;
    • @JoinTable中name表示中間關聯關系表名
    • @JoinTable中的joinColumns表示主鏈接表的字段,即當前對象內對應的連接字段
    • @JoinTable中inverseJoinColumns表示被連接的表的外鍵字段

  6.Left Join、Inner join和@EntityGraph

    當使用@ManyToMany、@ManytoOne、@OneToMany、@OneToOne關聯關系的時候SQL執行查詢的時候總是一條主查詢語句和N條子查詢語句組成,運行的效率較地下,如果子對象有N個就會執行N+1條SQL,JPA2.1推出的@EntityGraph、@NamedEntityGraph用來提高查詢效率@NamedEntityGraph配置在@Entity上面,而@EntityGraph配置在Repository的查詢方法上面

@NamedEntityGraph(name = "User.addressEntityList",attributeNodes = {@NamedAttributeNode("setRole"),@NamedAttributeNode("dept")})
@Entity
@Table(name="user")
public class User implements Serializable{
    private Long userId;
    @OneToMany(cascade = CascadeType.ALL,fetch = FetchType.LAZY,mappedBy = "user")
    @OrderBy("role_name DESC")
    private Set<Role> setRole;

    @OneToOne
    @JoinColumn(name = "dept_id",referencedColumnName = "user_id")
    private Department dept;
}

  然后只需要在Repository查詢方法上面加上@EntityGraph注解即可,其中value就是@NamedEntityGraph中的Name,配置如下

@EntityGraph(value ="User.addressEntityList")
List<User> findAll();

對於關系查詢需要注意以下事項:

  • 所有的注解要么全部配置在字段上,要么全部配置在get方法上面,不能混用,混用項目就會啟動不起來
  • 所有關聯都支持單雙向關聯。當JSON序列化的時候使用雙向注解會產生死循環,需要人為手動轉換一次,或者使用@JsonIgnore

  • 所有的關聯表一般不需要建立外鍵索引


免責聲明!

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



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