java PersistentObjectException:分离的实体传递给持久化

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7668804/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 20:55:42  来源:igfitidea点击:

PersistentObjectException: detached entity passed to persist

javahibernatejpaplayframework

提问by siamii

In my app I'm connected to a websocket. The socket is sending JSON data. As it is becoming available I process it in a different Job. In each job, I convert the JSON to a model object with GSON. There are 3 types of models, all independent, and with one common timestamp field in a MappedSuperclass. They don't have an id explicit field. I call save on the model and in 1 out of 1000 times a "PersistentObjectException: detached entity passed to persist" is thrown.

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

The multiple jobs are called from a start up Job that connects to the websocket. The library I'm using creates a different thread for each incoming message. I then convert the thread into a job before saving to the database. I do this, because otherwise another PersistentObjectException is thrown about changing the id from 1 to 2 or something similar, if I allow the original thread to call save.

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

I also have another job running that accesses the database at the same time. What could be wrong?

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

@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;
 }

EDIT:Added some code sample

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

采纳答案by siamii

I've found this workaround to work for now. Maybe it's to do with how Gson and Jpa interact. Not sure...

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

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

回答by millhouse

Basically it means the EntityManagerwon't track them any more: This is a good overview. Howthey come to be considered detached when you didn't explicitly ask for it is odd. But the workaround mightbe to use a "defensive" approach in your DAO method and mergethese odd cases; i.e.:

基本上这意味着EntityManager不会再跟踪它们:这是一个很好的概述。当您没有明确要求时,它们如何被认为是超脱的,这很奇怪。但是解决方法可能是在您的 DAO 方法和merge这些奇怪的情况下使用“防御性”方法;IE:

public void save (Model possiblyDetachedModel) {

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

I don't particularly like it, because it shouldn't need to be done when you're persisting brand-new objects. It might be worth putting some logging in (or debugging if at all possible) the "merge" branch and really inspecting those rogue objects - I'm pretty sure the EntityManagercan only use the @Idfield as the detection mechanism...

我不是特别喜欢它,因为当你正在persist处理全新的对象时,它不应该需要完成。可能值得在“ merge”分支中进行一些登录(或调试,如果可能的话)并真正检查那些流氓对象 - 我很确定EntityManager只能使用该@Id字段作为检测机制......