簡體   English   中英

使用@TableGenerator的JPA EclipseLink。 事務回滾后,為什么分配給id的值不為null?

[英]JPA EclipseLink with @TableGenerator. Why is the value assigned to id not null after transaction rollback?

我有以下實體:

@Entity
@Table(name = "sales", schema = "cust_tables")
@Multitenant(MultitenantType.TABLE_PER_TENANT)
@TenantTableDiscriminator(contextProperty = "customer_schema", type = TenantTableDiscriminatorType.SCHEMA)
@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
public class Sale implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "Sale")
    @TableGenerator(name = "Sale", schema = "thehub", allocationSize = 5)
    @Column(name = "id", unique = true, nullable = false, updatable = false)
    @XmlElement
    private Long id;

在持久操作期間,我可能有意讓事務在樂觀鎖定失敗期間回滾。

但是,在這種情況下,我對JPA / EclipseLink的行為感到驚訝。 JPA按預期將序列中的值分配給id 但是,在回滾期間,該值不會被“清空”。 然后,下次我嘗試保留時, id的值已經存在。 JPA跳過從序列中提取新數字並嘗試保留實體。

我因SQL完整性約束異常而失敗:

Caused by: javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.0.v20130226-e0971b1): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '51' for key 'PRIMARY'
Error Code: 1062

我究竟做錯了什么?

當JPA事務失敗時,所有對象都將分離。 您無法重新提交交易。

您需要創建一個新的持久性上下文,或者需要重新創建對象,或者如果您想使用現有的對象仔細地合並,則可以合並到新的持久性上下文中,並使它們的ID無效。 同樣,對於任何更新的對象,您將需要還原其版本字段。

JPA沒有提供簡單的方法來重新提交事務。 EclipseLink的本機API提供commitAndResumeOnFailure(),但是JPA並未公開。 也許記錄一個增強請求,以獲得某種允許在JPA中重新提交失敗的事務的選項。

好的,我設法弄清楚了,我將在這里發布結果,以幫助可能遇到相同問題的任何人。

使用調試器,即使在事務回滾期間,我也可以看到EclipseLink確實確實將值分配給了object.id字段。 如果您像我一樣,則將對id字段進行注釋,並且您的ID是不可變的,這意味着只有一個getter而不是setter。 EclipseLink能夠使用反射將值分配給該字段,但是公開的API可以防止id字段發生突變。 (這是一件“好事”)。

EclipseLink似乎是通過設計還是通過錯誤來為ID字段分配一個值,並從ID序列中刪除該值。 因此,事務回滾將在您的序列號中造成漏洞(這實際上並不是很大的犯罪)。

請記住,EclipseLink讀取序列號表,在內存中緩存一些序列號,然后在緩存為空時重新讀取它,同時為下一個序列提交起始值。

通過某種方式,通過事務回滾和重新啟動服務器的組合,序列號表落后於實際使用的序列號。 因此,該錯誤未在事務回滾期間分配ID,該錯誤失去了對序列號的跟蹤。 我最后得到的是序列號表的值為50,但數據庫中編號最高的實體為51。解決方案是將序列表更新為兩倍的distributionSize(5),將其設置為60,然后反彈我的服務器。

不幸的是,我無法重現此錯誤。 :(我不知道EclipseLink如何進入格式錯誤的狀態。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM