JPA

Java Persistence API

1. 基本注解

1.1 @Entity

@Entity 定義的對(duì)象會(huì)成為被 JPA 管理的實(shí)體超陆,將映射到指定的數(shù)據(jù)庫(kù)表中庇勃。

public @interface Entity {
    //可選,默認(rèn)是此實(shí)體類(lèi)名攒驰,全局唯一
    String name() default "";
}

1.2 @Table

用于指定數(shù)據(jù)庫(kù)的表名头岔。

public @interface Table {
    //表的名字,如果不寫(xiě),則默認(rèn)與實(shí)體的名字一樣
    String name() default "";
    //此表的catalog
    String catalog() default "";
    //此表的schema
    String schema() default "";
    //唯一性約束延欠,只有創(chuàng)建表的時(shí)候用,默認(rèn)不需要
    UniqueConstraint[] uniqueConstraints() default {};
    //索引沈跨,只有創(chuàng)建表的時(shí)候使用由捎,默認(rèn)不需要
    Index[] indexes() default {};
}

1.3 @Id

定義數(shù)據(jù)庫(kù)的主鍵,一個(gè)實(shí)體里至少有一個(gè)主鍵饿凛。

1.4 @IdClass

聯(lián)合主鍵狞玛。

public @interface IdClass {
    //聯(lián)合主鍵的類(lèi)
    Class value();
}

聯(lián)合主鍵的用處就是一個(gè)表中能存在多個(gè)主鍵,這些主鍵在關(guān)聯(lián)在外部的一個(gè)對(duì)象中涧窒,這個(gè)對(duì)象需要滿(mǎn)足以下條件

  • 必須實(shí)現(xiàn) Serializable 接口
  • 必須有默認(rèn)的 public 無(wú)參構(gòu)造方法
  • 必須覆蓋 equals()hashCode() 方法

1.5 @GeneratedValue

主鍵生成策略心肪。

public @interface GeneratedValue {
    //Id生成策略,默認(rèn)GenerationType.AUTO
    GenerationType strategy() default GenerationType.AUTO;
    //通過(guò)Sequences生成Id纠吴,常見(jiàn)的是Orcale數(shù)據(jù)庫(kù)的Id生成規(guī)則硬鞍,需要配合@SequenceGenerator使用
    String generator() default "";
}

public enum GenerationType {
    //通過(guò)表產(chǎn)生主鍵,框架由表模擬序列產(chǎn)生主鍵戴已,使用該策略可以使應(yīng)用更易于數(shù)據(jù)庫(kù)移植
    TABLE,
    //通過(guò)序列產(chǎn)生主鍵固该,通過(guò)@SequenceGenerator注解指定序列名,Mysql不支持這種方式
    SEQUENCE,
    //采用數(shù)據(jù)庫(kù)Id自增恭陡,用于Mysql數(shù)據(jù)庫(kù)
    IDENTITY,
    //JPA默認(rèn)選項(xiàng)蹬音,自動(dòng)選擇策略
    AUTO;

    private GenerationType() {
    }
}

1.6 @Basic

@Basic 表示屬性是到數(shù)據(jù)庫(kù)的字段的映射,如果實(shí)體的字段上沒(méi)有任何注解休玩,默認(rèn)為 @Basic著淆。

public @interface Basic {
    //EAGER是立即加載,這是默認(rèn)方式拴疤,可以看到還有一種LAZY懶加載
    FetchType fetch() default FetchType.EAGER;
    //Optional 類(lèi)是一個(gè)可以為null的容器對(duì)象永部,設(shè)置為true,則表示字段可以為null呐矾,默認(rèn)可以
    boolean optional() default true;
}

public enum FetchType {
    LAZY,
    EAGER;

    private FetchType() {
    }
}

1.7 @Transient

@Transient 表示該屬性并非一個(gè)到數(shù)據(jù)庫(kù)表的字段的映射苔埋,是非持久化屬性,與 @Basic 作用相反蜒犯。

實(shí)體中有數(shù)據(jù)庫(kù)中不存在的字段组橄,可以加上 @Transient 注解,忽略這個(gè)字段的映射罚随。

1.8 @Column

public @interface Column {
    String name() default "";
    //表示該字段是否為唯一標(biāo)識(shí)玉工,默認(rèn)為false,如果表中有一個(gè)字段需要唯一標(biāo)識(shí)淘菩,則既可以使用該標(biāo)記遵班,也可以使用@Table標(biāo)記中的@UniqueConstraint
    boolean unique() default false;
    //數(shù)據(jù)字段是否允許為空,默認(rèn)允許
    boolean nullable() default true;
    //執(zhí)行insert操作時(shí)是否包含此字段,默認(rèn)包含
    boolean insertable() default true;
    //執(zhí)行update操作時(shí)是否包含此字段狭郑,默認(rèn)包含
    //insertable和updatable屬性一般多用于只讀的屬性腹暖,例如主鍵和外鍵等。這些字段的值通常是自動(dòng)生成的
    boolean updatable() default true;
    //表示創(chuàng)建表時(shí)翰萨,該字段創(chuàng)建的SQL語(yǔ)句脏答,一般用于通過(guò)Entity生成表定義時(shí)使用
    String columnDefinition() default "";
    //表示當(dāng)映射多個(gè)表時(shí),指定表的表中的字段亩鬼。默認(rèn)值為主表的表名
    String table() default "";
    //字段長(zhǎng)度以蕴,默認(rèn)255
    int length() default 255;
    // precision 屬性和 scale 屬性表示精度,當(dāng)字段類(lèi)型為double時(shí)辛孵,precision表示數(shù)值的總長(zhǎng)度,scale表示小數(shù)點(diǎn)所占的位數(shù)
    int precision() default 0;
    int scale() default 0;
}

1.9 @Temporal

@Temporal 用來(lái)設(shè)置 Date 類(lèi)型的屬性映射到對(duì)應(yīng)精度的字段赡磅,也就是對(duì)日期進(jìn)行格式化魄缚。

public enum TemporalType {
    DATE,
    TIME,
    TIMESTAMP;

    private TemporalType() {
    }
}

public @interface Temporal {
    TemporalType value();
}

public enum TemporalType {
    DATE,
    TIME,
    TIMESTAMP;

    private TemporalType() {
    }
}

可以看到有三種格式化方式,

  1. @Temporal(TemporalType.DATE): 實(shí)體類(lèi)會(huì)封裝成日期 yyyy-MM-dd 的 Date 類(lèi)型焚廊。
  2. @Temporal(TemporalType.TIME): 實(shí)體類(lèi)會(huì)封裝成時(shí)間 hh-MM-ss 的 Date 類(lèi)型冶匹。
  3. @Temporal(TemporalType.TIMESTAMP): 實(shí)體類(lèi)會(huì)封裝成完整的時(shí)間 yyyy-MM-dd hh:MM:ss 的 Date 類(lèi)型。

1.10 @Enumerated

用于直接映射枚舉類(lèi)型的字段咆瘟。

public @interface Enumerated {
    EnumType value() default EnumType.ORDINAL;
}

1.11 @Lob

@Lob 將屬性映射為數(shù)據(jù)庫(kù)支持的大對(duì)象類(lèi)型嚼隘,支持以下兩種數(shù)據(jù)庫(kù)類(lèi)型的字段。

  • Clob:長(zhǎng)字符串類(lèi)型袒餐,java.sql.Clob飞蛹、Character[]char[]灸眼、String 都將被映射成 Clob 類(lèi)型卧檐。
  • Blob:字節(jié)類(lèi)型,java.sql.Blob焰宣、Byte[]霉囚、byte[]、實(shí)現(xiàn)了 Serializable 接口類(lèi)型都將被映射成 Blob 類(lèi)型匕积。

2. JPA 中的實(shí)體關(guān)系

簡(jiǎn)單地用原始字段持久化一個(gè)對(duì)象只是等式的一半盈罐。JPA 還具有管理彼此相關(guān)的實(shí)體的能力。表和對(duì)象中都可能存在四種實(shí)體關(guān)系:

  • 一對(duì)多
  • 多對(duì)一
  • 多對(duì)多
  • 一對(duì)一

2.1 @JoinColumn

定義外鍵關(guān)聯(lián)的字段名稱(chēng)闪唆。

public @interface JoinColumn {
    //注解所在當(dāng)前表的主鍵名盅粪,必須寫(xiě)
    String name() default "";
    //關(guān)聯(lián)外部表的列名,默認(rèn)是外部主鍵名
    String referencedColumnName() default "";
    //外鍵字段是否唯一
    boolean unique() default false;
    //外鍵字段是否允許為空
    boolean nullable() default true;
    //是否跟隨一起新增
    boolean insertable() default true;
    //是否跟隨一起更新
    boolean updatable() default true;
    
    String columnDefinition() default "";

    String table() default "";

    ForeignKey foreignKey() default @ForeignKey(ConstraintMode.PROVIDER_DEFAULT);
}

配合 @OneToOne苞氮、@OneToMany湾揽、@ManyToOne 一起使用。

2.2 關(guān)系映射注解

public @interface OneToOne {
    //關(guān)系目標(biāo)實(shí)體,默認(rèn)為該字段的類(lèi)型
    Class targetEntity() default void.class;
    
    //級(jí)聯(lián)操作策略
    CascadeType[] cascade() default {};

    //數(shù)據(jù)獲取方式库物,立即加載和延遲加載
    FetchType fetch() default FetchType.EAGER;

    boolean optional() default true;

    //關(guān)聯(lián)關(guān)系被誰(shuí)維護(hù)霸旗,一般不需要特別指定, 只有關(guān)系維護(hù)方才能操作兩者的關(guān)系,被維護(hù)方即使設(shè)置了維護(hù)方屬性進(jìn)行存儲(chǔ)也不會(huì)更新外鍵關(guān)聯(lián)
    //mappedBy不能與@JoinColumn或者@JoinTable同時(shí)使用
    //mappedBy的值是指另一方的實(shí)體里屬性的字段戚揭,而不是數(shù)據(jù)庫(kù)字段诱告,也不是實(shí)體的對(duì)象的名字,是另一方配置了@JoinColumn或者@JoinTable注解的屬性的字段名稱(chēng)
    String mappedBy() default "";

    //是否級(jí)聯(lián)刪除民晒,和 CascadeType.REMOVE 的效果一樣精居,只是配置了兩種中的一種就會(huì)自動(dòng)級(jí)聯(lián)刪除
    boolean orphanRemoval() default false;
}

public enum CascadeType { 
    ALL, 
    PERSIST, 
    MERGE, 
    REMOVE,
    REFRESH
}

級(jí)聯(lián)操作策略代碼舉例解釋

public class Student {
    @ManyToMany(cascade=CascadeType.PERSIST, fetch=FetchType.LAZY)
    private Set<Course> courses = new HashSet<>();
}
  1. CascadeType.PERSIST 級(jí)聯(lián)新建:若 Student 實(shí)體持有的 Course 實(shí)體在數(shù)據(jù)庫(kù)中不存在時(shí),Student 保存時(shí)自動(dòng)在 Course 實(shí)體對(duì)應(yīng)的數(shù)據(jù)庫(kù)中保存 Course 數(shù)據(jù)潜必。
  2. CascadeType.MERGE 級(jí)聯(lián)更新:當(dāng) Student 中的數(shù)據(jù)改變靴姿,會(huì)相應(yīng)地更新 Course 中的數(shù)據(jù)。
  3. CascadeType.REMOVE 級(jí)聯(lián)刪除:刪除 Student 實(shí)體磁滚,與它有映射關(guān)系的 Course 實(shí)體也會(huì)跟著被刪除佛吓。
  4. CascadeType.REFRESH 級(jí)聯(lián)刷新:Student 保存時(shí)重新加載 Course 關(guān)系
  5. CascadeType.DETACH 級(jí)聯(lián)脫離:要?jiǎng)h除一個(gè)實(shí)體,直接撤銷(xiāo)所有相關(guān)的外鍵關(guān)聯(lián)
  6. CascadeType.ALL 擁有以上所有級(jí)聯(lián)操作權(quán)限
  7. 默認(rèn)垂攘,關(guān)系表不會(huì)產(chǎn)生任何影響

@OneToOne 需要配合 @JoinColumn 一起使用

在使用@OneToOne進(jìn)行雙向關(guān)聯(lián)時(shí)维雇,需要在類(lèi)上加上注解 @JsonIdentityInfo,這個(gè)注解被用來(lái)在序列化/反序列化時(shí)為該對(duì)象或字段添加一個(gè)對(duì)象識(shí)別碼晒他,通常是用來(lái)解決循環(huán)嵌套的問(wèn)題吱型。通過(guò)配置屬性 generator 來(lái)確定識(shí)別碼生成的方式,配置屬性 property 來(lái)確定識(shí)別碼的名稱(chēng)陨仅,識(shí)別碼名稱(chēng)沒(méi)有限制津滞。

一般這個(gè)注解可以這么加

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")

@OneToMany@ManyToOne 同上。

2.3 @OrderBy

用于關(guān)聯(lián)查詢(xún)時(shí)排序掂名。

@Entity 
public class Course {
    ...
    @ManyToMany
    @OrderBy("lastname ASC")
    public List  getStudents() {...};
    ...
}

@Entity 
public class Student {
    ...
    @ManyToMany(mappedBy="students")
    @OrderBy //默認(rèn)使用主鍵排序
    public List  getCourses() {...};
    ...
}

3. 查詢(xún)

注意: 這里是接口据沈,是 persistence-api 包中的,項(xiàng)目里 Repository 里的接口上面實(shí)現(xiàn)的 @Query 注解不是下面這個(gè)饺蔑,spring-data-jpa 的查詢(xún)和解析留待下回分解

/**
 * Interface used to control query execution.
 *
 * @since Java Persistence 1.0
 */
public interface Query {

    /**
     * Execute a SELECT query and return the query results
     * as a List.
     * @return a list of the results
     * @throws IllegalStateException if called for a Java 
     *    Persistence query language UPDATE or DELETE statement
     */   
    public List getResultList();

    /**
     * Execute a SELECT query that returns a single result.
     * @return the result
     * @throws NoResultException if there is no result
     * @throws NonUniqueResultException if more than one result
     * @throws IllegalStateException if called for a Java 
     *    Persistence query language UPDATE or DELETE statement
     */
    public Object getSingleResult();

    /**
     * Execute an update or delete statement.
     * @return the number of entities updated or deleted
     * @throws IllegalStateException if called for a Java 
     *    Persistence query language SELECT statement
     * @throws TransactionRequiredException if there is
     *    no transaction
     */
    public int executeUpdate();

    /**
     * Set the maximum number of results to retrieve.
     * @param maxResult
     * @return the same query instance
     * @throws IllegalArgumentException if argument is negative
     */
    public Query setMaxResults(int maxResult);

    /**
     * Set the position of the first result to retrieve.
     * @param startPosition the start position of the first result, numbered from 0
     * @return the same query instance
     * @throws IllegalArgumentException if argument is negative
     */
    public Query setFirstResult(int startPosition);

    /**
     * Set an implementation-specific hint.
     * If the hint name is not recognized, it is silently ignored.
     * @param hintName
     * @param value
     * @return the same query instance
     * @throws IllegalArgumentException if the second argument is not
     *    valid for the implementation
     */
    public Query setHint(String hintName, Object value);

    /**
     * Bind an argument to a named parameter.
     * @param name the parameter name
     * @param value
     * @return the same query instance
     * @throws IllegalArgumentException if parameter name does not
     *    correspond to parameter in query string
     *    or argument is of incorrect type
     */
    public Query setParameter(String name, Object value);

    /**
     * Bind an instance of java.util.Date to a named parameter.
     * @param name
     * @param value
     * @param temporalType
     * @return the same query instance
     * @throws IllegalArgumentException if parameter name does not
     *    correspond to parameter in query string
     */
    public Query setParameter(String name, Date value, TemporalType temporalType);

    /**
     * Bind an instance of java.util.Calendar to a named parameter.
     * @param name
     * @param value
     * @param temporalType
     * @return the same query instance
     * @throws IllegalArgumentException if parameter name does not
     *    correspond to parameter in query string
     */
    public Query setParameter(String name, Calendar value, TemporalType temporalType);

    /**
     * Bind an argument to a positional parameter.
     * @param position
     * @param value
     * @return the same query instance
     * @throws IllegalArgumentException if position does not
     *    correspond to positional parameter of query
     *    or argument is of incorrect type
     */
    public Query setParameter(int position, Object value);

    /**
     * Bind an instance of java.util.Date to a positional parameter.
     * @param position
     * @param value
     * @param temporalType
     * @return the same query instance
     * @throws IllegalArgumentException if position does not
     *    correspond to positional parameter of query
     */
    public Query setParameter(int position, Date value, TemporalType temporalType);

    /**
     * Bind an instance of java.util.Calendar to a positional parameter.
     * @param position
     * @param value
     * @param temporalType
     * @return the same query instance
     * @throws IllegalArgumentException if position does not
     *    correspond to positional parameter of query
     */
    public Query setParameter(int position, Calendar value, TemporalType temporalType);

    /**
     * Set the flush mode type to be used for the query execution.
     * The flush mode type applies to the query regardless of the
     * flush mode type in use for the entity manager.
     * @param flushMode
     */
    public Query setFlushMode(FlushModeType flushMode);
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末锌介,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子猾警,更是在濱河造成了極大的恐慌孔祸,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件发皿,死亡現(xiàn)場(chǎng)離奇詭異崔慧,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)穴墅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)惶室,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)温自,“玉大人,你說(shuō)我怎么就攤上這事皇钞〉棵冢” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵夹界,是天一觀(guān)的道長(zhǎng)馆里。 經(jīng)常有香客問(wèn)我,道長(zhǎng)可柿,這世上最難降的妖魔是什么鸠踪? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮复斥,結(jié)果婚禮上营密,老公的妹妹穿的比我還像新娘。我一直安慰自己目锭,他們只是感情好卵贱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著侣集,像睡著了一般。 火紅的嫁衣襯著肌膚如雪兰绣。 梳的紋絲不亂的頭發(fā)上世分,一...
    開(kāi)封第一講書(shū)人閱讀 51,155評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音缀辩,去河邊找鬼臭埋。 笑死,一個(gè)胖子當(dāng)著我的面吹牛臀玄,可吹牛的內(nèi)容都是我干的瓢阴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼健无,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼荣恐!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起累贤,我...
    開(kāi)封第一講書(shū)人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤叠穆,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后臼膏,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體硼被,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年渗磅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嚷硫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片检访。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖仔掸,靈堂內(nèi)的尸體忽然破棺而出脆贵,到底是詐尸還是另有隱情,我是刑警寧澤嘉汰,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布丹禀,位于F島的核電站,受9級(jí)特大地震影響鞋怀,放射性物質(zhì)發(fā)生泄漏双泪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一密似、第九天 我趴在偏房一處隱蔽的房頂上張望焙矛。 院中可真熱鬧,春花似錦残腌、人聲如沸村斟。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蟆盹。三九已至,卻和暖如春闺金,著一層夾襖步出監(jiān)牢的瞬間逾滥,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工败匹, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留寨昙,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓掀亩,卻偏偏與公主長(zhǎng)得像舔哪,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子槽棍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容