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

daz*_*ito 12 java hibernate jpa

我正在创建一个简单的应用程序,只是在表中插入一行(如果表不存在,创建它)使用Java JPA.

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

这是我得到的例外和堆栈跟踪:

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
Run Code Online (Sandbox Code Playgroud)

这是我的代码:

主要课程:

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();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

和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() {
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的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>
Run Code Online (Sandbox Code Playgroud)

-----------------------编辑-------------------------- -

我刚刚将提供程序更改为EclipseLink,并且没有进一步的更改它正在工作.我现在很困惑.为什么它适用于EclipseLink但是使用Hibernate会产生异常?

Man*_*and 16

这样做的原因是您已经在Person类中声明了使用自动策略生成的id,这意味着JPA尝试在持久化实体时插入id本身.但是在你constructor手动设置id变量.由于ID是手动分配的,并且实体不存在persistence context于此中,因此会JPA认为您正在尝试保留与持久性上下文分离的实体,从而导致异常.

要修复它,不要在构造函数中设置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;
  }
Run Code Online (Sandbox Code Playgroud)

  • 当您事先知道 ID 时,您还可以执行“EntityManager.merge”操作而不是“EntityManager.persist”操作... (2认同)

Ank*_*hal 14

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

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

assigned - 允许应用程序在调用之前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() {
    }
}
Run Code Online (Sandbox Code Playgroud)