【问题标题】:PersistentObjectException: detached entity passed to persistPersistentObjectException:分离的实体传递给持久化
【发布时间】:2011-10-05 23:10:12
【问题描述】:

在我的应用程序中,我已连接到 websocket。 套接字正在发送 JSON 数据。随着它变得可用,我在另一个工作中处理它。在每个作业中,我都使用 GSON 将 JSON 转换为模型对象。有 3 种类型的模型,它们都是独立的,并且在 MappedSuperclass 中具有一个公共时间戳字段。他们没有 id 显式字段。我在模型上调用 save ,并且在 1000 次中有 1 次抛出“PersistentObjectException:传递给持久化的分离实体”。

从连接到 websocket 的启动 Job 调用多个作业。我正在使用的库为每条传入消息创建一个不同的线程。然后我将线程转换为作业,然后保存到数据库。我这样做是因为如果我允许原始线程调用保存,则会引发另一个关于将 id 从 1 更改为 2 或类似内容的 PersistentObjectException。

我还有另一个正在运行的作业同时访问数据库。有什么问题?

@Override
public void onMessage(final WebSocketMessage message){
        new Job() {
            @Override
            public void doJob() {
                processMessage(message.getText());
            }
        }.now();

}

 public void processMessage(String message) {
        Appointment appointment = new Gson().fromJson(message, Appointment.class);
        appointment.save();
 }

 @Entity
 public class Appointment extends CalendarEvent {
       private String owner;
 }

 @MappedSuperclass
 public abstract class CalendarEvent extends Model {
       private long timestamp;
 }

编辑:添加了一些代码示例

【问题讨论】:

  • 如何识别模型对象? @Id 字段中的值是否可能是非唯一的?
  • 每个模型类都有一个 id 字段,即为空。我的课程扩展了模型。他们本身并没有声明一个 id 字段。
  • 顺便说一句,我不太明白这条消息的含义。 “分离的实体传递给坚持”在英语中是什么意思? (我不是母语人士)

标签: java hibernate jpa playframework


【解决方案1】:

基本上这意味着EntityManager 将不再跟踪它们:This is a good overview如何当你没有明确要求时,他们会被认为是超然的,这很奇怪。但解决方法可能是在您的 DAO 方法中使用“防御性”方法和merge 这些奇怪的情况;即:

public void save (Model possiblyDetachedModel) {

   if (entityManager.contains(possiblyDetachedModel)) {
        entityManager.merge(possiblyDetachedModel);
    } else {
        entityManager.persist(possiblyDetachedModel);
    }
}

我不是特别喜欢它,因为当您persisting 全新对象时不需要这样做。可能值得在“merge”分支中进行一些登录(或调试)并真正检查那些流氓对象 - 我很确定EntityManager 只能使用@Id 字段作为检测机制...

【讨论】:

  • 感谢您的链接。我找到了一个现在似乎可行的解决方法......
【解决方案2】:

我发现这个解决方法现在可行。也许这与 Gson 和 Jpa 的交互方式有关。不确定...

public void processMessage(String message) {
        Appointment appointment = new Gson().fromJson(message, Appointment.class);
        //recreate appointment
        appointment = new Appointment(appointment);
        appointment.save();  }

【讨论】:

  • 必须。多么奇怪。我假设您的 Appointment 复制构造函数始终明确地将 id 设置为 null 从而确保它被视为 EntityManager 的“新”。
猜你喜欢
  • 2015-12-26
  • 2012-11-02
  • 1970-01-01
  • 2019-12-10
  • 1970-01-01
相关资源
最近更新 更多