2014-09-03 63 views
12

我正在創建一個簡單的應用程序,使用Java JPA向表中插入一行(如果表不存在,創建它)。org.hibernate.PersistentObjectException:傳遞給persist的獨立實體 - 與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 

這裏是我的代碼:

主要類:

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(); 
      } 
     } 
    } 
} 

,而該人等級:

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() { 
    } 
} 

這是我的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> 

-----------------------編輯---------- -----------------

我剛剛將供應商更改爲EclipseLink,並且不再進行任何更改。我現在很困惑。爲什麼它與EclipseLink一起工作,但是使用Hibernate它會產生異常?

回答

13

請嘗試使用下面的代碼,然後它將允許您手動設置ID

只需使用@Id註釋,它可以讓您定義哪個屬性是您的實體的標識符。如果您不希望休眠爲您生成此屬性,則不需要使用@GeneratedValue註釋。

分配 - 允許應用程序在調用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() { 
    } 
} 
12

原因是您已聲明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; 
    } 
+0

如果我真的需要在構造函數上設置id,該怎麼辦? – dazito 2014-09-03 04:21:59

+0

在這種情況下,您不應該使用AUTO策略將其聲明爲@GeneratedValue – 2014-09-03 04:25:15

+0

@dwnz回答發佈 – 2014-09-03 04:30:14

2

在已註釋的ID類定義由持久性提供選擇的策略(表,序列等)來產生,但通過構造初始化Person對象的id。我認爲留ID空可能會解決您的問題。

+0

是的,它解決了我的問題。但它產生了另一個問題,如果我真的需要在對象構造函數上設置一個id,該怎麼辦? – dazito 2014-09-03 04:28:23

+0

爲什麼你需要手動設置ID?該id必須由持久性提供者分配。 – Ammaro 2014-09-03 04:30:32

+0

因爲我將在'JTable'中顯示數據,然後將其插入數據庫。我想保留'JTable'中的數據與數據庫表中的數據同步。我不想去數據庫檢索所有的數據(我已經有了),這樣我就可以更新'JTable'中的id並且不會同步(id @ JTable!= id @ DBTable) – dazito 2014-09-03 04:35:38

0

您可以使用此contrustor這樣的:

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

那麼當JPA持久化到數據庫,它會自動AUTO_INCREMENT策略插入。

相關問題