gpt4 book ai didi

java - OpenJPA 不规则地抛出 EntityExistsException

转载 作者:行者123 更新时间:2023-12-01 09:28:20 28 4
gpt4 key购买 nike

我有一个新的(即尚未出现在数据库中)JPA 实体,它使用以下代码保存到数据库中:

public abstract class Dao {
@PersistenceContext(name = "puOpenJPA_Core",type = PersistenceContextType.TRANSACTION)
private EntityManager em;

public void save(Fund entity) {
entity = em.merge(entity);
em.flush();

// do something with entity.fundId
}
}

我们需要flush,因为我们使用对象的id来填充其他内容,并且id是在数据库上生成的。

实体看起来像这样:

@Entity
public class Fund extends AbstractFund implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "fundId")
protected Long id;

// other fields and getters etc.

}

AbstractFund 是一个具有更多字段的抽象映射父类(super class)。

数据库中的表将 fundId 列定义为身份。长期以来,这一切都运行良好。然而,当调用 flush 时,我们遇到了间歇性错误。部署后,代码工作正常一段时间,然后突然开始抛出此异常:

Caused by: <openjpa-2.3.0-r422266:1540826 fatal general error> org.apache.openjpa.persistence.PersistenceException: 
The transaction has been rolled back. See the nested exceptions for details on the errors that occurred.
FailedObject: entities.Fund@1097fef5
at org.apache.openjpa.kernel.BrokerImpl.newFlushException(BrokerImpl.java:2370) [openjpa-all-2.3.0.jar:2.3.0]
at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:2207) [openjpa-all-2.3.0.jar:2.3.0]
at org.apache.openjpa.kernel.BrokerImpl.flushSafe(BrokerImpl.java:2105) [openjpa-all-2.3.0.jar:2.3.0]
at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:1876) [openjpa-all-2.3.0.jar:2.3.0]
at org.apache.openjpa.kernel.DelegatingBroker.flush(DelegatingBroker.java:1045) [openjpa-all-2.3.0.jar:2.3.0]
at org.apache.openjpa.persistence.EntityManagerImpl.flush(EntityManagerImpl.java:663) [openjpa-all-2.3.0.jar:2.3.0]
at org.jboss.as.jpa.container.AbstractEntityManager.flush(AbstractEntityManager.java:457) [wildfly-jpa-8.1.0.Final.jar:8.1.0.Final]
......
Caused by: java.lang.Exception: <openjpa-2.3.0-r422266:1540826 fatal store error> org.apache.openjpa.persistence.EntityExistsException:
Cannot insert explicit value for identity column in table 'Fund' when IDENTITY_INSERT is set to OFF. {prepstmnt 2128975916 INSERT INTO Fund
(fundId, ... other columns ...) VALUES (?, ?, ?, )} [code=544, state=23000]
FailedObject: entities.Fund@1e7b1cce
at org.apache.openjpa.util.Exceptions.replaceNestedThrowables(Exceptions.java:255) [openjpa-all-2.3.0.jar:2.3.0]
at org.apache.openjpa.persistence.PersistenceException.writeObject(PersistenceException.java:100) [openjpa-all-2.3.0.jar:2.3.0]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.7.0_60]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [rt.jar:1.7.0_60]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.7.0_60]
at java.lang.reflect.Method.invoke(Method.java:606) [rt.jar:1.7.0_60]
at org.jboss.marshalling.reflect.SerializableClass.callWriteObject(SerializableClass.java:271)
at org.jboss.marshalling.cloner.SerializingCloner.initSerializableClone(SerializingCloner.java:290)
at org.jboss.marshalling.cloner.SerializingCloner.clone(SerializingCloner.java:245)
at org.jboss.marshalling.cloner.SerializingCloner.clone(SerializingCloner.java:125)
at org.jboss.marshalling.cloner.SerializingCloner.cloneFields(SerializingCloner.java:341)
at org.jboss.marshalling.cloner.SerializingCloner.initSerializableClone(SerializingCloner.java:293)
at org.jboss.marshalling.cloner.SerializingCloner.initSerializableClone(SerializingCloner.java:277)
at org.jboss.marshalling.cloner.SerializingCloner.initSerializableClone(SerializingCloner.java:277)
at org.jboss.marshalling.cloner.SerializingCloner.initSerializableClone(SerializingCloner.java:277)
at org.jboss.marshalling.cloner.SerializingCloner.initSerializableClone(SerializingCloner.java:277)
at org.jboss.marshalling.cloner.SerializingCloner.clone(SerializingCloner.java:245)
at org.jboss.marshalling.cloner.SerializingCloner.clone(SerializingCloner.java:125)
at org.jboss.as.ejb3.remote.LocalEjbReceiver.clone(LocalEjbReceiver.java:314) [wildfly-ejb3-8.1.0.Final.jar:8.1.0.Final]
at org.jboss.as.ejb3.remote.LocalEjbReceiver.clone(LocalEjbReceiver.java:297) [wildfly-ejb3-8.1.0.Final.jar:8.1.0.Final]
at org.jboss.as.ejb3.remote.LocalEjbReceiver.processInvocation(LocalEjbReceiver.java:249) [wildfly-ejb3-8.1.0.Final.jar:8.1.0.Final]
... 126 more

我无法在其他环境中重新创建此内容,并且不明白为什么 OpenJPA 会突然开始尝试为标识列插入值。

我们正在使用 OpenJPA 版本 2.3.0。

我已尝试更新到版本 2.4.1,但问题仍然存在。

最佳答案

首先,恕我直言,我不确定 Prashant Katara 的回答有何用意。我不知道您需要执行选择/复制/保留的场景?克里斯提供了一些很好的评论。虽然我无法确切地说出这个问题是如何发生的,但让我提供一些有关您如何陷入麻烦的信息,可能是零星的 - 或特定于环境的 - 正如您所指出的。在您的描述中,您发布了此“保存”方法:

public void save(Fund entity) {
em.merge(entity);
em.flush();
}

然后您说“我们需要刷新,因为我们使用 id......”。这里有一些相关的事情。如您所见,您合并了传递到保存中的“实体”。但是,您永远不会返回从“em.merge”返回的对象。 OpenJPA 可能不会填充“实体”中的 id,而只会填充合并返回的 id 值!人们总是忘记传递给合并的实例不是托管实例!从合并返回的实例是受管理的!既然您声明您需要 id 的值,我假设您实际上在调用保存后使用“实体”,因此您应该使用托管实例(即“em.merge”返回的实例)。这不是一个安全的操作,而且我很惊讶如果您在刷新后调用fundId的getter方法,您不会得到“null”。如果你从不,重复从不,在调用保存后使用“实体”,那么我想你的保存方法没问题。但是,如果您打算在保存后继续使用该实体,那么您的保存应如下所示:

public Fund save(Fund entity) {
Fund entityPrime = em.merge(entity);
em.flush();
return entityPrime;
}

最后,OpenJPA 不会发出包含 IDENTIFICATION 字段的字段/列的 INSERT。所以你永远不应该看到其中包含fundId 的INSERT。我不明白你是如何陷入 INSERT 包含fundId的情况的。可能是您的类路径中的某处可能有旧版本的 Fund,其中不包含“@GenerateValue(strategy = GenerationType.IDENTITY)”。作为 INSERT 操作的一部分,从数据库返回 IDENTIFICATION 值,然后 OpenJPA 将该返回值分配给(托管)IDENTIFICATION 字段。

谢谢

希斯

关于java - OpenJPA 不规则地抛出 EntityExistsException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39659049/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com