1

我有以下实体:

@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 的行为感到惊讶。id正如预期的那样,JPA 将序列中的值分配给。但是,在回滚期间,该值不会被“删除”。然后下次我尝试坚持时, for 的值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

我究竟做错了什么?

4

2 回答 2

2

当 JPA 事务失败时,所有对象都将分离。您不能重新提交交易。

您需要创建一个新的持久性上下文,并且需要重新创建对象,或者如果您想使用现有的对象,请仔细合并到新的持久性上下文中并清空它们的 id。此外,对于任何更新的对象,您都需要恢复其版本字段。

JPA 不提供重新提交事务的简单方法。EclipseLink 的本机 API 提供了 commitAndResumeOnFailure(),但这并没有暴露给 JPA。也许记录增强请求以获得某种选项以允许在 JPA 中重新提交失败的事务。

于 2013-04-03T13:26:58.190 回答
0

好的,我设法解决了这个问题,我将在此处发布我的结果以帮助可能遇到相同问题的任何人。

使用调试器,我可以看到 EclipseLink 确实为 entity.id 字段分配了一个值,即使在事务回滚期间也是如此。如果你像我一样,你的 id 字段被注释并且你的 ID 是不可变的,这意味着只有一个 getter 而不是一个 setter。EclipseLink 能够使用反射为该字段分配一个值,但您公开的 API 会阻止 id 字段的突变。(这是一件“好事”)。

EclipseLink 似乎有意或无意地为 ID 字段分配了一个值,并从 ID 序列中删除了该值。因此,事务回滚会导致您的序列号出现漏洞(这并不是什么大罪)。

请记住,EclipseLink 读取序列号表,在内存中缓存一些序列号,然后在缓存为空时重新读取它,同时为下一个序列提交起始值。

不知何故,通过事务回滚和重新启动我的服务器的组合,序列号表落后于正在使用的实际序列号。因此,该错误不是在事务回滚期间分配 ID,而是丢失了对序列号的跟踪。我最终得到的是序列号表的值为 50,但我的数据库中编号最高的实体是 51。解决方案是将序列表更新为 allocationSize(5) 的两倍,将其设置为 60,然后反弹我的服务器。

不幸的是,我无法重现此错误。:( 我不知道 EclipseLink 是如何进入格式错误的状态的。

于 2013-04-03T15:31:55.103 回答