最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring?Data?JPA?實體類中常用注解說明

 更新時間:2021年11月22日 15:15:01   作者:半雨微涼  
這篇文章主要介紹了Spring?Data?JPA?實體類中常用注解說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

javax.persistence 介紹

Spring Data JPA 采用約定大于配置的思想,默認(rèn)了很多東西

JPA是存儲業(yè)務(wù)實體關(guān)聯(lián)的實體來源,它顯示定義了如何定義一個面向普通Java對象(POJO)作為實體,以及如何與管理關(guān)系實體提供一套標(biāo)準(zhǔn)

javax.persistence位于hibernate-jpa-**.jar 包里面

jpa類層次結(jié)構(gòu):

JPA類層次結(jié)構(gòu)的顯示單元:

單元 描述
EntityManagerFactory 一個EntityManager的工廠類,創(chuàng)建并管理多個EntityManager實例
EntityManager 一個接口,管理持久化操作的對象,工廠原理類似工廠的查詢實例
Entity 實體是持久性對象,是存儲在數(shù)據(jù)庫中的記錄
EntityTransaction 與EntityManager是一對一的關(guān)系,對于每一個EntityManager的操作由EntityTransaction類維護
Persistence 這個類包含靜態(tài)方法來獲取EntityManagerFactory實例
Query 該接口由每個JPA供應(yīng)商實現(xiàn),能夠獲得符合標(biāo)準(zhǔn)的關(guān)系對象

基本注解

@Entity

@Entity定義對象將會成為被JPA管理的實體,將映射到指定的數(shù)據(jù)庫表

public @interface Entity {
    String name() default "";
}

@Table

@Table指定數(shù)據(jù)庫的表名

public @interface Table {
    // 表的名字,可選,默認(rèn)實體類名為表的名稱(駝峰命名規(guī)則)
    String name() default "";
    // 此表的catlog,可選
    String catalog() default "";
    // 此表所在的schema,可選
    String schema() default "";
    // 唯一性約束,只有在創(chuàng)建表的時候有用,默認(rèn)不需要
    UniqueConstraint[] uniqueConstraints() default {};
    // 索引,只有創(chuàng)建表的時候有用,默認(rèn)不需要
    Index[] indexes() default {};
}

@Id

定義屬性為數(shù)據(jù)庫中的主鍵,一個實體必須有一個

@IdClass

@IdClass利用外部類的聯(lián)合主鍵

public @interface IdClass {
     // 聯(lián)合主鍵的類
    Class value();
}
  • 作為聯(lián)合主鍵類,需要滿足以下要求:
  • 必須實現(xiàn)Serializable
  • 必須有默認(rèn)的public無參構(gòu)造方法
  • 必須覆蓋equals和hashCode方法(EntityManager通過find方法查找Entity時是根據(jù)equals來判斷的)

用法:

(1)假設(shè)user_article表中的聯(lián)合主鍵是 title 與create_user_id,聯(lián)合主鍵類代碼如下:

@Data
public class UserArticleKey implements Serializable {
    private String title;
    private Long createUserId;
    public UserArticleKey() {
    }
    public UserArticleKey(String title, String content, Long createUserId) {
        this.title = title;
        this.createUserId = createUserId;
    }
}

(2)user_article表實體類如下:

@Entity
@IdClass(value = UserArticleKey.class)
@Data
public class UserArticle {
    private Integer id;
    @Id
    private String title;
    @Id
    private Long createUserId;
}

(3) repository 類如下:

public interface ArticleRepository extends JpaRepository<UserArticle, UserArticleKey> {
}

(4)調(diào)用代碼如下:

@Test
public void testUnionKey(){
    Optional<UserArticle> userArticle = this.articleRepository.findById(new UserArticleKey("新聞",1L));
    if (userArticle.isPresent()){
        System.out.println(userArticle.get());
    }
}

@GenerateValue

主鍵生成策略

public @interface GeneratedValue {
    // Id 的生成策略
    GenerationType strategy() default GenerationType.AUTO;
    // 通過 Sequence生成Id, 常見Oracle生成規(guī)則,需要配合@SequenceGenerator使用
    String generator() default "";
}

GenerationType

public enum GenerationType {
    // 通過表產(chǎn)生主鍵,框架由表模擬序列產(chǎn)生主鍵(有益于數(shù)據(jù)庫移植)
    TABLE,
    // 通過序列產(chǎn)生主鍵,通過@SequenceGenerator注解指定序列名,不支持MySQL
    SEQUENCE,
    // 采用數(shù)據(jù)ID自增長,一般用于MySQL
    IDENTITY,
    // JPA自動適配的策略,默認(rèn)選項
    AUTO;
    private GenerationType() {
    }
}

@Basic

屬性是到數(shù)據(jù)表的字段的映射,實體類上的字段沒有注解時默認(rèn)為@Basic

public @interface Basic {
    // 可選,默認(rèn)為立即加載(EAGER),LZAY延遲加載(應(yīng)用在大字段上)
    FetchType fetch() default FetchType.EAGER;
    // 可選,設(shè)置這個字段是否可為null,默認(rèn) true
    boolean optional() default true;
}

@Transient

表示該屬性并非一個到數(shù)據(jù)庫表的字段的映射,表示非持久化屬性,與@Basic作用相反,JPA映射的時候會忽略@Transient標(biāo)記的字段

@Column

定義屬性對應(yīng)數(shù)據(jù)庫中的列名

public @interface Column {
    // 是語句庫中表的列名, 默認(rèn)字段名和屬性名一樣, 可選
    String name() default "";
    // 是否唯一,默認(rèn) false, 可選
    boolean unique() default false;
    // 是否允許空, 默認(rèn) true, 可選
    boolean nullable() default true;
    // 執(zhí)行insert操作的時候是否包含此字段,默認(rèn) true, 可選
    boolean insertable() default true;
    // 執(zhí)行update操作的時候是否包含此字段,默認(rèn) true, 可選
    boolean updatable() default true;
    // 該字段在數(shù)據(jù)庫中的實際類型
    String columnDefinition() default "";
    // 當(dāng)映射多個表時,指在哪張表的字段,默認(rèn)為主表
    String table() default "";
    // 字段長度,字段類型為VARCHAR時有效
    int length() default 255;
    // 精度,當(dāng)字段類型為double時候, precision表示數(shù)值總長度
    int precision() default 0;
    // 精度, 當(dāng)字段類型為double時候, scale表示小數(shù)位數(shù)
    int scale() default 0;
}

@Temporal

用來設(shè)置Date 類型的屬性映射到對應(yīng)精度的字段

  • @Temporal(Temporal.DATE) 映射為日期
  • @Temporal(Temporal.TIME) 映射為日期(只有時間)
  • @Temporal(Temporal.TIMESTAMP) 映射為日期(日期+時間)

@Enumerated

映射menu枚舉類型的字段

源碼:

public @interface Enumerated {
    // 映射枚舉的類型
    EnumType value() default EnumType.ORDINAL;
}
public enum EnumType {
    // 映射枚舉字段的下標(biāo)
    ORDINAL,
    // 映射枚舉的name
    STRING;
}

如果使用 ORDINAL 在數(shù)據(jù)庫中則會存儲 0,1,2,3 這是一個索引值,這個索引值是由enum中元素的位置決定,如果enum中元素位置出現(xiàn)不正確的變動

很可能與數(shù)據(jù)庫中的數(shù)據(jù)無法對應(yīng),建議使用 STRING

用法:

@Entity(name = "t_user")
@Data
@Table
public class SystemUser implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Basic
    private String uname;
    private String email;
    private String address;
    @Enumerated(EnumType.STRING)
    @Column(name = "user_gender")
    private Gender sex;
    public enum Gender{
        MALE("男性"),
        FEMALE("女性")
        ;
        private String value;
        Gender(String value) {
            this.value = value;
        }
    }
}

@Lob

映射成數(shù)據(jù)庫支持的大對象類型

  • Clob(Character Large Objects) 類型是長字符串類型java.sql.Clob、Character[]、char[]和String將被映射為Clob類型
  • Blob(Binary Large Objects) 類型是字節(jié)型,java.sql.Blob,Byte[]、byte[]和實現(xiàn)了Serializable接口的類型將被映射為Blob類型
  • Clob、Blob占用內(nèi)存空間較大,一般配合@Basic(fetch=FetchType.LAZY)將其設(shè)置為延遲加載

@NamedNativeQueries、@NamedNativeQuerie、@SqlResultSetMappings、@SqlResultSetMapping、@ColumnResult

這幾個注解一般配合使用,實際情況中不會自定義這些配置

@NamedNativeQueries({
        @NamedNativeQuery(
                name = "getUsers",
                query = "select id,title,create_user_id,create_date from user_article order by create_date desc",
                resultSetMapping = "userArticleMap"
        )
})
@SqlResultSetMappings({
        @SqlResultSetMapping(
                name = "userArticleMap",
                entities = {},
                columns = {
                        @ColumnResult(name = "id"),
                        @ColumnResult(name = "title"),
                        @ColumnResult(name = "createUserId"),
                        @ColumnResult(name = "createDate"),
                }
        )
})
@Entity
@IdClass(value = UserArticleKey.class)
@Data
public class UserArticle {
    @Column
    private Integer id;
    @Id
    private String title;
    @Id
    private Long createUserId;
    private Date createDate;
}

關(guān)聯(lián)關(guān)系注解

@JoinColumn 定義外鍵關(guān)聯(lián)的字段名稱

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

@JoinColumns 定義多個字段的關(guān)聯(lián)關(guān)系

public @interface JoinColumn {
    // 目標(biāo)表的字段名,必填
    String name() default "";
    // 本實體類的字段名, 非必填, 默認(rèn)本表ID
    String referencedColumnName() default "";
    // 外鍵字段是否唯一, 可選
    boolean unique() default false;
    // 外鍵字段是否允許為空, 可選
    boolean nullable() default true;
    // 是否跟隨一起新增, 可選
    boolean insertable() default true;
    // 是否跟隨一起更新, 可選
    boolean updatable() default true;
    // 生成DDL的時候使用的SQL片段 可選
    String columnDefinition() default "";
    // 包含列的表的名稱 , 可選
    String table() default "";
    // 外鍵約束類別, 默認(rèn)為 默認(rèn)約束行為, 可選
    ForeignKey foreignKey() default @ForeignKey(ConstraintMode.PROVIDER_DEFAULT);
}

@OneToOne 一對一關(guān)聯(lián)關(guān)系

public @interface OneToOne {
    // 關(guān)系目標(biāo)實體, 默認(rèn)為void.class, 可選
    Class targetEntity() default void.class;
    // 級聯(lián)操作策略, PERSIST(級聯(lián)新增)、REMOVE(級聯(lián)刪除)、REFRESH(級聯(lián)刷新)、MERGE(級聯(lián)更新)、ALL(全選)
    // 默認(rèn)表不會產(chǎn)生任何影響
    CascadeType[] cascade() default {};
    // 數(shù)據(jù)獲取方式,EAGER(立即加載)、LAZY(延遲加載)
    FetchType fetch() default EAGER;
    // 是否允許空
    boolean optional() default true;
    // 關(guān)聯(lián)關(guān)系被誰維護,非必填,一遍不需要特別指定
    // mappedBy不能與@JoinColumn或者@JoinTable同時使用
    // mappedBy的值是指另一方的實體里面屬性的字段,而不是數(shù)據(jù)庫字段,也不是實體的對象的名字,即另一方配置了@JoinColumn或者@JoinTable注解的屬性的字段名稱
    String mappedBy() default "";
    
    // 是否級聯(lián)刪除,和CascadeType.REMOVE 效果一樣,任意配置一種即可生效
    boolean orphanRemoval() default false;
}

用法:

@OneToOne
// name 為當(dāng)前實體對應(yīng)數(shù)據(jù)庫表中的字段名
// referencedColumnName 為 SystemUser 實體中@Id標(biāo)記的字段對應(yīng)的數(shù)據(jù)庫字段名
@JoinColumn(name = "create_user_id",referencedColumnName = "id")
private SystemUser createUser = new SystemUser();

雙向關(guān)聯(lián):

@OneToOne(mappedBy = "createUser")
private UserArticle article = new UserArticle();

等價于mappedBy:

@OneToOne
@JoinColumn(name = "user_article_id",referencedColumnName = "id")
private UserArticle article = new UserArticle();

@OneToMany 與 @ManyToOne 一對多與多對一關(guān)聯(lián)關(guān)系

OneToMany與ManyToOne可以相對存在,也可只存在一方

public @interface OneToMany {
    Class targetEntity() default void.class;
    // 級聯(lián)操作策略
    CascadeType[] cascade() default {};
    // 數(shù)據(jù)獲取方式
    FetchType fetch() default LAZY;
    // 關(guān)系被誰維護,單項的
    String mappedBy() default "";
    // 是否級聯(lián)刪除
    boolean orphanRemoval() default false;
}
public @interface ManyToOne {
    Class targetEntity() default void.class;
    // 級聯(lián)操作策略
    CascadeType[] cascade() default {};
    // 數(shù)據(jù)獲取方式
    FetchType fetch() default LAZY;     // 關(guān)聯(lián)是否可選。如果設(shè)置,若要為false,則必須始終存在非null關(guān)系。
    boolean optional() default true;
}

@ManyToOne 映射的是一個實體對象

@Entity
@Data
public class UserArticle {
    @Column
    private Integer id;
    @Id
    private String title;
    @ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
    @JoinColumn(name = "create_user_id",referencedColumnName = "id")
    private SystemUser systemUser = new SystemUser();
    private Date createDate;
}

@OneToMany 映射的是一個是列表

@Entity(name = "t_user")
@Data
@Table
public class SystemUser implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Basic
    private String uname;
    private String email;
    private String address;
    @Enumerated(EnumType.STRING)
    private Gender sex;
@OneToMany
// name 當(dāng)前表id
// create_user_id 目標(biāo)表的關(guān)聯(lián)字段
@JoinColumn(name = "id",referencedColumnName = "create_user_id")
private List<UserArticle> articleList = new ArrayList<>();
    public enum Gender{
        MALE("男性"),
        FEMALE("女性")
        ;
        private String value;
        Gender(String value) {
            this.value = value;
        }
    }
}

@OrderBy 排序關(guān)聯(lián)查詢

與@OneToMany一起使用

public @interface OrderBy {
    /**
     * 要排序的字段格式如下:
     *    orderby_list::= orderby_item [,orderby_item]*
     *    orderby_item::= [property_or_field_name] [ASC | DESC]
     * 字段可以是實體屬性,也可以是數(shù)據(jù)字段,默認(rèn)ASC
     */
    String value() default "";
}

用法:

@OneToMany
@JoinColumn(name = "id",referencedColumnName = "create_user_id")
@OrderBy("createDate DESC") // createDate 是 UserArticle 的實體屬性
private List<UserArticle> articleList = new ArrayList<>();
 

@JoinTable 關(guān)聯(lián)關(guān)系表

對象與對象之間有關(guān)聯(lián)關(guān)系表的時候就用到,@JoinTable, 與@ManyToMany一起使用

public @interface JoinTable {
    // 中間關(guān)聯(lián)關(guān)系表名
    String name() default "";
    // 表的 catalog
    String catalog() default "";
    // 表的 schema
    String schema() default "";
    // 主連接表的字段
    JoinColumn[] joinColumns() default {};
    // 被連接表的字段
    JoinColumn[] inverseJoinColumns() default {};
    // 主連接外鍵約束類別
    ForeignKey foreignKey() default @ForeignKey(PROVIDER_DEFAULT);
    // 被連接外鍵約束類別
    ForeignKey inverseForeignKey() default @ForeignKey(PROVIDER_DEFAULT);
    // 唯一約束
    UniqueConstraint[] uniqueConstraints() default {};
    // 表的索引
    Index[] indexes() default {};
}

用法:

@Entity
// 主連接表 blog
public class Blog {
    @ManyToMany
    @JoinTable(
            name = "blog_tag_relation", // 關(guān)系表名稱
            joinColumns = @JoinColumn(name = "blog_id",referencedColumnName = "id"), // 主連接表配置
            inverseJoinColumns = @JoinColumn(name = "tag_id",referencedColumnName = "id") // 被連接表配置
    )
    // tag 是被連接表
    private List<Tag> tags = new ArrayList<>();
}

關(guān)于雙向多對多:

雙向多對多需要建立 @JoinTable的實體里, 在被連接表中的@ManyToMany中使用mappedBy="BlogTagRelation"進行配置

LeftJoin 與 Inner Join 可以提高查詢效率

當(dāng)使用@ManyToMany、@ManyToOne、@OneToMany、@OneToOne關(guān)聯(lián)時候,SQL真正執(zhí)行的時候,由一條主表查詢和N條子表查詢組成

會產(chǎn)生N+1問題

為了簡單的提高查詢效率,使用EntityGraph可以解決N+1條SQL的問題

@EntityGraph

@EntityGraph、@NamedEntityGraph用來提高查詢效率(很好的解決了N+1條SQL的問題),兩者需要配合使用,缺一不可

實體類:

@NamedEntityGraph(
        name = "Blog.tags", attributeNodes = {
        @NamedAttributeNode("tags")
}
)
@Entity
// 主連接表 blog
public class Blog {
    @ManyToMany
    @JoinTable(
            name = "blog_tag_relation", // 關(guān)系表名稱
            joinColumns = @JoinColumn(name = "blog_id", referencedColumnName = "id"), // 主連接表配置
            inverseJoinColumns = @JoinColumn(name = "tag_id", referencedColumnName = "id") // 被連接表配置
    )
    // tag 是被連接表
    private List<Tag> tags = new ArrayList<>();
}

repository:

public interface BlogRepository extends JpaRepository<Blog,Long> {
    @Override
    @EntityGraph(value = "Blog.tags")
    List<Blog> findAll();
}

關(guān)于關(guān)系查詢的一些注意事項

所有注解要么全配置在字段上,要么配置在get方法上,不能混用,會無法啟動

所有的關(guān)聯(lián)都是支持單向關(guān)聯(lián)和雙向關(guān)聯(lián)的,JSON序列化的時候使用雙向注解會產(chǎn)生死循環(huán),需要手動轉(zhuǎn)化一次或使用@JsonIgnore

在所有的關(guān)聯(lián)查詢中,表一般是不需要簡歷外鍵索引的,@mappedBy的使用需要注意

級聯(lián)刪除比較危險,建議考慮清楚或完全掌握

不同的關(guān)聯(lián)關(guān)系的配置,@JoinColumn里面的name,referencedColumnName代表的意思是不一樣的

當(dāng)配置這些關(guān)聯(lián)關(guān)系的時候建議直接在表上把外鍵關(guān)系簡歷好,然后用開發(fā)工具直接生成,這樣可以減少調(diào)試時間

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java類和成員上的一些方法實例代碼

    Java類和成員上的一些方法實例代碼

    這篇文章主要介紹了Java類和成員上的一些方法實例代碼,具有一定借鑒價值,需要的朋友可以參考下
    2018-01-01
  • 解析Java異步之call future

    解析Java異步之call future

    當(dāng)調(diào)用一個函數(shù)的時候,如果這個函數(shù)的執(zhí)行過程是很耗時的,就必須要等待,但是有時候并不急著要這個函數(shù)返回的結(jié)果。因此,可以讓被調(diào)者立即返回,讓他在后臺慢慢處理這個請求。對于調(diào)用者來說,可以先處理一些其他事情,在真正需要數(shù)據(jù)的時候再去嘗試獲得需要的數(shù)據(jù)
    2021-06-06
  • IDEA 端口占用的解決方法(推薦)

    IDEA 端口占用的解決方法(推薦)

    這篇文章主要介紹了IDEA 端口占用的解決方法,本文通過兩種方法給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-10-10
  • 使用idea生成springboot程序的docker鏡像的操作指南

    使用idea生成springboot程序的docker鏡像的操作指南

    這篇文章給大家詳細(xì)的介紹了使用idea生成springboot程序的docker鏡像的操作指南,文中通過圖文結(jié)合給大家講解的非常詳細(xì),具有一定的參考價值,需要的朋友可以參考下
    2023-12-12
  • JVM虛擬機的執(zhí)行流程解析

    JVM虛擬機的執(zhí)行流程解析

    這篇文章主要介紹了JVM虛擬機的執(zhí)行流程圖解,Java虛擬機的啟動是通過引導(dǎo)類加載器創(chuàng)建一個初始類來完成的,這個類是由虛擬機的具體實現(xiàn)指定的,程序開始執(zhí)行時他才運行,程序結(jié)束時他就停止,需要的朋友可以參考下
    2023-08-08
  • Mybatis中BindingException異常的產(chǎn)生原因及解決過程

    Mybatis中BindingException異常的產(chǎn)生原因及解決過程

    BindingException異常是MyBatis框架中自定義的異常,顧名思義指的是綁定出現(xiàn)問題,下面這篇文章主要給大家介紹了關(guān)于MyBatis報錯BindingException異常的產(chǎn)生原因及解決過程,需要的朋友可以參考下
    2023-06-06
  • Servlet開發(fā)JavaWeb工程示例詳解

    Servlet開發(fā)JavaWeb工程示例詳解

    這篇文章主要介紹了Servlet開發(fā)JavaWeb工程示例詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • WebSocket 中使用 @Autowired 注入對應(yīng)為null的解決方案

    WebSocket 中使用 @Autowired 注入對應(yīng)為null的解決方案

    SpringBoot集成WebSocket時,會遇到service對象為null的情況,原因是Spring默認(rèn)為單例模式與WebSocket的多對象模式相沖突,當(dāng)客戶端與服務(wù)器端建立連接時,會創(chuàng)建新的WebSocket對象,本文給大家介紹WebSocket 中使用 @Autowired 注入對應(yīng)為null的問題,感興趣的朋友一起看看吧
    2024-10-10
  • 深入Java萬物之母Object類詳情

    深入Java萬物之母Object類詳情

    這篇文章主要介紹了Java萬物之母Object類詳情,Object類,它是所有類的默認(rèn)父類 ,子類不用使用extends關(guān)鍵字繼承它,不管是JDK中的類,還是自定義的類
    2022-06-06
  • SpringBoot下實現(xiàn)session保持方式

    SpringBoot下實現(xiàn)session保持方式

    這篇文章主要介紹了SpringBoot下實現(xiàn)session保持方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03

最新評論

徐闻县| 米泉市| 饶平县| 新乐市| 峨眉山市| 淄博市| 皮山县| 三门峡市| 玛多县| 涟源市| 崇文区| 徐汇区| 鹤壁市| 岳阳县| 沾益县| 定结县| 三台县| 江油市| 黄山市| 平泉县| 大新县| 龙泉市| 双鸭山市| 新竹县| 达日县| 郧西县| 张家口市| 康乐县| 达尔| 梁河县| 贺州市| 四子王旗| 神池县| 宁强县| 柘荣县| 元氏县| 文成县| 伽师县| 孝义市| 巨野县| 广汉市|