[英]When does the JPA set a @GeneratedValue @Id
我有一個簡單的 JPA 實體,它使用生成的long
“ID”作為其主鍵:
@Entity
public class Player {
private long id;
protected Player() {
// Do nothing; id defaults to 0L
}
@GeneratedValue
@Id
public long getId() {
return id;
}
protected void setId(final long id) {
this.id = id;
}
// Other code
}
在此類型對象的生命周期中的某個時刻,JPA 必須調用setId()
來記錄生成的 ID 值。 我的問題是,這什么時候發生,說明這一點的文檔在哪里。 我已經查看了 JPA 規范,但找不到明確的聲明。
JPA 規范說(強調):
受管實體實例是具有當前與持久上下文相關聯的持久標識的實例。
這是想說必須管理對象才能使其@Id
有意義嗎? EntityManager.persist()
的文檔說(強調)它使“實例管理和持久化”,那么這是否意味着@Id
是由該方法設置的? 還是直到您調用EntityTransaction.commit()
?
對於不同的 JPA 提供者,以及可能對於不同的生成策略,設置@Id
時間可能會有所不同。 但是,您可以對生命周期中的最早點做出的最安全(便攜、符合規范)假設是什么?
調用 .persist() 不會自動設置 id 值。 您的 JPA 提供程序將確保在實體最終寫入 db 之前設置它。 因此,您可以假設在提交事務時分配 id 是正確的。 但這並不是唯一可能的情況。 當你調用 .flush() 時,同樣會發生。
托馬斯
更新:請注意 Geek 的評論。 -> 如果使用 GenerationType.Identity,則在實體寫入 db 之前提供者不會設置 id。 在這種情況下,id 生成發生在 db 級別的插入過程中。 無論如何,JPA 提供者將確保實體隨后更新,並且生成的 id 將在 @Id 注釋屬性中可用。
AFAIK,只有在刷新持久性上下文時才保證分配 ID。 它可能會更快分配,但這取決於生成策略。
Rubinger 和 Burke所著的 Enterprise JavaBeans 3.1一書在第 143 頁(添加了強調)如下:
Java Persistence 還可以配置為在通過使用主鍵字段或 setter 頂部的
@GeneratedValue
注釋調用persist()
方法時自動生成主鍵。 因此,在前面的示例中,如果我們啟用了自動密鑰生成,則可以在persist()
方法完成后查看生成的密鑰。
JPA 規范說(強調):
受管實體實例是具有當前與持久上下文相關聯的持久標識的實例。
還有EntityManager.persist()
使得
一個實例管理和持久化
由於@Id
對實體的身份至關重要,因此EntityManager.persist()
管理對象的唯一方法是通過生成@Id
來建立其身份。
然而
Rubinger 和 Buke 的明確聲明與 Hibernate 的行為不一致。 因此,似乎知識淵博的人不同意 JPA 規范的意圖。
根據JSR 338: JavaTM Persistence 2.1 / 3.5.3 Semantics of the Life Cycle Callback Methods for Entities ,
PostPersist
和PostRemove
回調方法在實體被持久化或刪除后被調用。 這些回調也將在這些操作級聯到的所有實體上調用。PostPersist
和PostRemove
方法將分別在數據庫插入和刪除操作之后被調用。 這些數據庫操作可能在調用持久、合並或刪除操作之后直接發生,也可能在刷新操作發生后(可能在事務結束時)直接發生。 生成的主鍵值在PostPersist
方法中可用。
一種可能的(個人推測的)異常是GeneratorType.TABLE
,容器(可能)獲取要使用的值並(可能)在PrePersist
之前設置它。 我總是在PrePersist
使用我的id
。 我不確定此行為是否已指定或可能不適用於任何其他供應商。
重要編輯
並非所有應用程序服務器都在PrePersist
之前設置 id。 您可以跟蹤JPA_SPEC 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.