Java org.hibernate.PersistentObjectException:分离的实体传递给持久异常

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25636091/
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-08-11 00:50:06  来源:igfitidea点击:

org.hibernate.PersistentObjectException: detached entity passed to persist exception

javahibernatejpa

提问by dazito

I'm creating a simple app to just insert a row to a table (if table does not exist, create it) using Java JPA.

我正在创建一个简单的应用程序,只需使用Java JPA.

I'm attaching some code for a runnable example of it.

我正在为它的可运行示例附加一些代码。

Here's the exception I'm getting and the stacktrace:

这是我得到的异常和堆栈跟踪:

EXCEPTION -- > org.hibernate.PersistentObjectException: detached entity passed to persist: view.Person
javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: view.Person
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1763)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1683)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1187)
    at view.TestJPA.main(TestJPA.java:34)
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: view.Person
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:139)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:811)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1181)
    ... 1 more

And here is my code:

这是我的代码:

Main class:

主要类:

package view;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

public class TestJPA {

    public static void main(String[] args) {

        Person p = new Person(1, "Peter", "Parker");

        EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("TesePersistentUnit");
        EntityManager entityManager = entityManagerFactory.createEntityManager();

        EntityTransaction transaction = entityManager.getTransaction();
        try {
            transaction.begin();

            entityManager.persist(p);
            entityManager.getTransaction().commit();
        } 
        catch (Exception e) {
            if (transaction != null) {
                transaction.rollback();
            }
            System.out.println("EXCEPTION -- > " + e.getMessage());
            e.printStackTrace();
        } 
        finally {
            if (entityManager != null) {
                entityManager.close();
            }
        }
    }
}

And the Person class:

和 Person 类:

package view;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "People")
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    private String name;
    private String lastName;

    public Person(int id, String name, String lastName) {
        this.id = id;
        this.name = name;
        this.lastName = lastName;
    }

    public Person() {
    }
}

And here's my persistence.xml file

这是我的 persistence.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="TesePersistentUnit" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <class>view.Person</class>
        <properties>
            <!-- SQL dialect -->
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>

            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/tese_tabelas?zeroDateTimeBehavior=convertToNull"/>
            <property name="javax.persistence.jdbc.user" value="root"/>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.password" value=""/>

            <!-- Create/update tables automatically using mapping metadata -->
            <property name="hibernate.hbm2ddl.auto" value="update"/>
        </properties>
    </persistence-unit>
</persistence>

----------------------- EDIT ---------------------------

- - - - - - - - - - - - 编辑 - - - - - - - - - - - - - ——

I just changed the provider to EclipseLink and with no further changes it is working. I'm confused now. Why does it works with EclipseLink but with Hibernate it generates an exception?

我只是将提供程序更改为 EclipseLink,并且没有进一步更改它正在工作。我现在很困惑。为什么它可以与 EclipseLink 一起使用,但与 Hibernate 一起使用它会生成异常?

采纳答案by Ankur Singhal

Try with the below code then, it will allow you to set the IDmanually.

然后尝试使用以下代码,它将允许您ID手动设置。

Just use the @Idannotation which lets you define which property is the identifier of your entity. You don't need to use the @GeneratedValueannotation if you do not want hibernate to generate this property for you.

只需使用@Id可让您定义哪个属性是实体标识符的注释。@GeneratedValue如果您不希望 hibernate 为您生成此属性,则不需要使用注释。

assigned- lets the application to assign an identifier to the object before save()is called. This is the default strategy if no <generator>element is specified.

分配- 让应用程序在调用之前save()为对象分配一个标识符。如果未<generator>指定元素,则这是默认策略。

package view;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "People")
public class Person {
    @Id
    //@GeneratedValue(strategy = GenerationType.AUTO) // commented for manually set the id
    private int id;

    private String name;
    private String lastName;

    public Person(int id, String name, String lastName) {
        this.id = id;
        this.name = name;
        this.lastName = lastName;
    }

    public Person() {
    }
}

回答by Manjunath Anand

The reason for this is that you have declared the id in Personclass as generated with auto strategy meaning JPAtries to insert the id itself while persisting the entity. However in your constructoryou are manually setting the id variable . Since the ID is manually assigned, and that the entity is not present in the persistence contextthis causes JPAto think that you are trying to persist an entity which is detached from persistence context and hence the exception.

这样做的原因是您已将Person类中的 id 声明为使用自动策略生成,这意味着JPA尝试在持久化实体的同时插入 id 本身。但是,在您constructor手动设置 id 变量。由于 ID 是手动分配的,并且实体不存在于persistence contextthis 中JPA,因此认为您正在尝试持久化与持久化上下文分离的实体,因此出现异常。

To fix it dont set the id in the constructor.

要修复它,请不要在构造函数中设置 id。

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;



public Person(int id, String name, String lastName) {
       // this.id = id;
        this.name = name;
        this.lastName = lastName;
  }

回答by Ammaro

In the class definition you have annotated id to be generated by strategy (table, sequence, etc.) chosen by the persistence provider, but you are initializing the id of the Person object through constructor. I think leaving id null may solve your problem.

在类定义中,您已将 id 注释为由持久性提供者选择的策略(表、序列等)生成,但您正在通过构造函数初始化 Person 对象的 id。我认为让 id null 可以解决您的问题。

回答by Minh Nguyen

You can use this contrustor like this:

您可以像这样使用这个委托人:

Person p = new Person(0, "Peter", "Parker");

then when JPA persist to database it'll automatically insert with AUTO_INCREMENTstrategy.

然后当 JPA 持久化到数据库时,它会自动插入AUTO_INCREMENT策略。