Frage

Unten ist mein Testcode:

package jee.jpa2;

import java.util.List;

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

import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@Test
public class Tester {
    EntityManager em;
    EntityTransaction tx;
    EntityManagerFactory emf;

    @BeforeClass
    public void setup() {
        emf = Persistence.createEntityManagerFactory("basicPU", System.getProperties());
    }

    @Test
    public void insert() {
        Item item = new Item();
        for (int i = 0; i < 1000; ++i) {
            em = emf.createEntityManager();
            tx = em.getTransaction();
            tx.begin();
            item.setId(null);
            em.persist(item);
            tx.commit();
            em.clear();
            em.close();
            tx=null;
            em=null;
        }
    }

    @Test
    public void read() {
        em = emf.createEntityManager();
        tx = em.getTransaction();
        tx.begin();
        Query findAll = em.createNamedQuery("findAll");
        List<Item> all = findAll.getResultList();
        for (Item item : all) {
            System.out.println(item);
        }
        tx.commit();
    }
}

Und hier ist das Unternehmen:

package jee.jpa2;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;

@Entity
@NamedQuery(name="findAll", query="SELECT i FROM Item i")
public class Item {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID", nullable = false, updatable= false)
    protected Long id;
    protected String name;

    public Item() {
        name = "Digambar";
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return String.format("Item [id=%s, name=%s]", id, name);
    }

}

Nach dem Test Ausführen ich Fehler:

Item [id=1, name=Digambar]
Item [id=2, name=Digambar]
PASSED: read
FAILED: insert
<openjpa-2.0.0-r422266:935683 nonfatal store error> org.apache.openjpa.persistence.EntityExistsException: Attempt to persist detached object "jee.jpa2.Item-2".  If this is a new instance, make sure any version and/or auto-generated primary key fields are null/default when persisting.
FailedObject: jee.jpa2.Item-2
    at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2563)
    at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2423)
    at org.apache.openjpa.kernel.DelegatingBroker.persist(DelegatingBroker.java:1069)
    at org.apache.openjpa.persistence.EntityManagerImpl.persist(EntityManagerImpl.java:705)
    at jee.jpa2.Tester.insert(Tester.java:33)

Bitte was Erklären passiert hier?

War es hilfreich?

Lösung

Zur Beantwortung der Frage streng Titel, Laufzeitverbesserung erfolgt eine javaagent verwenden, die dynamisch geladen werden kann, wenn JDK 1.6 (dies ist dokumentiert in Entity Enhancement ).

In Bezug auf das Problem Sie konfrontiert, ich vermute, einen OpenJPA Bug zu sein (ich habe einige gesehen ähnlich Themen wie OpenJPA-755 ), ist die Fehlermeldung mit dem Code inkohärent, da Sie das Primärschlüsselfeld zu null sind Einstellung und haben keine Version Feld. Sie sollten es melden.

That being said, eine einfache Möglichkeit, „Abhilfe“ das Problem wäre eine neue Item Instanz innerhalb der Schleife zu erstellen. So etwas wie folgt aus:

public void insert() {
    for (int i = 0; i < 1000; ++i) {
        Item item = new Item();
        em = emf.createEntityManager();
        tx = em.getTransaction();
        tx.begin();
        em.persist(item);
        tx.commit();
        em.clear();
        em.close();
        tx=null;
        em=null;
    }
}

Zusätzliche Hinweise:

Warum sind vorbei Sie System.getProperties() wenn die EntityManagerFactory erstellen?

Sie sollten die EntityManagerFactory am Ende Ihres Tests schließen:

@AfterClass
public static void closeEntityManagerFactory() {
    emf.close();
}

Update: einen Kommentar beantworten. Aus der JPA-Spezifikation:

  

3.2 Entity Instanz Life Cycle

     

In diesem Abschnitt wird die   EntityManager-Operationen für die Verwaltung   ein Unternehmen Instanz Lebenszyklus. Ein   Entitätsinstanz kann charakterisiert werden   als neu, gelang es, freistehend, oder   entfernt.

     
      
  • A neue Entitätsinstanz hat keine persistente Identität ist und noch nicht   im Zusammenhang mit einem Persistenzkontext.
  •   
  • A verwaltet Entitätsinstanz ist eine Instanz mit einer persistenten Identität   , die derzeit mit einem zugehörigen   Persistenzkontext.
  •   
  • A freistehend Entitätsinstanz ist eine Instanz mit einer persistenten Identität   Das ist nicht (oder nicht mehr) zugeordnet   mit einem Persistenzkontext .
  •   
  • A entfernt Entitätsinstanz ist eine Instanz mit einer persistenten Identität,   in Verbindung mit einem Persistenzkontext,   , die für die Entfernung von der geplanten   Datenbank.
  •   

Wenn Sie also eine freistehende Einheit haben (das so ist nicht mit einem anhaltenden Kontext zugeordnet ), und wenn legen Sie die Id kommentierten Felder null (es hat also keine persistente Identität ), dann haben Sie genau das, was die Spezifikation definiert als eine neue Einheit, unabhängig von OpenJPA Verhalten. Deshalb habe ich diese betrachten einen Fehler in OpenJPA sein (und die Fehlermeldung ist inkohärent sowieso).

Andere Tipps

Punkt zu beachten, dass ist "Entity-Manager verfolgt die Spuren von Entitäten durch Java Object Referenzen."

Ich kann nur gleiche beharren Java-Objekt / Referenz immer wieder in for-Schleife, wenn und nur wenn ich emf = Persistence.createEntityManagerFactory("basicPU") Anweisung in for-Schleife bewegen. wie folgt aus:

Listing 1:

Item item = new Item(); 
    for (int i = 0; i < 1000; ++i) { 
        emf = Persistence.createEntityManagerFactory("basicPU");            
        em = emf.createEntityManager();         
        tx = em.getTransaction();
        tx.begin(); 
        item.setId(null); 
        em.persist(item); 
        tx.commit();
        em.clear();
        em.close(); 
    } 

Aber wenn die for-Schleife ist wie:

Listing 2:

Item item = new Item(); 
    emf = Persistence.createEntityManagerFactory("basicPU");     
    for (int i = 0; i < 1000; ++i) { 
        em = emf.createEntityManager();         
        tx = em.getTransaction();
        tx.begin(); 
        item.setId(null); 
        em.persist(item); 
        tx.commit();
        em.clear();
        em.close(); 
    } 

Ich erhalte die EntityExistException.

Bedeutet es, dass emf.createEntityManager () Methode gibt die zwischengespeicherte Kopie von EntityManager der Spur von Item-Objekt hält in vorheriger Iteration der for-Schleife anhielt.? a BIG NO. denn wenn ich versuchte, unten Linien auszuführen ..

emf = Persistence.createEntityManagerFactory("basicPU");
        for (int i = 0 ; i<10; i++){
                System.out.println(emf.createEntityManager());
        }

Es gedruckt ..

org.apache.openjpa.persistence.EntityManagerImpl@18105e8
org.apache.openjpa.persistence.EntityManagerImpl@9bad5a
org.apache.openjpa.persistence.EntityManagerImpl@91f005
org.apache.openjpa.persistence.EntityManagerImpl@1250ff2
org.apache.openjpa.persistence.EntityManagerImpl@3a0ab1
org.apache.openjpa.persistence.EntityManagerImpl@940f82
org.apache.openjpa.persistence.EntityManagerImpl@864e43
org.apache.openjpa.persistence.EntityManagerImpl@17c2891
org.apache.openjpa.persistence.EntityManagerImpl@4b82d2
org.apache.openjpa.persistence.EntityManagerImpl@179d854

Welche Mittel emf.createEntityManager () immer neue Instanz von EntityManager zurück.

So in Listing 1 und Listing 2, I bekommt immer neue EntityManager-Instanz und nach wie vor mit 1 Eintrag kann ich gleiches Objekt in der Datenbank bestehen, aber in Listing 2 I EntityExistException bekommen. Warum so?

ich denke, wenn ich neue EntityManager habe in beiden Anzeigen (1 und 2) Ich soll gleiches Objekt in der Datenbank bestehen bleiben kann, weil EntityManager Spur von Entitäten durch Referenzen Java-Objekts hält und in jeder Iteration ich neue EntityManager habe, die nicht wissen, oder nicht wissen sollte, die Objektreferenzen gespeichert / beharrte in der Datenbank in früheren Iteration durch eine andere EntityManager Objektinstanz.

Haben Sie sich den Quellcode einen Blick haben? Es ist tief in den Eingeweiden des Kernels:

http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java?view=markup

Line 2563

OpenJPA 2.0 kann Runtime-Enhancer dynamisch installieren, wenn auf JDK 1.6 (nicht JRE) ausgeführt wird, siehe docs . Technisch gesehen, heften sie dynamisch ein Java-Agenten mit API anhängen , wihtout Notwendigkeit -javaagent Option.

So wird die Item Klasse tatsächlich verbessert und Entity-Manager weiß, dass es eine freistehende Instanz trotz des null ids persistierenden und Schließen von Entity-Manager.

Die Fehlermeldung sagt Ihnen, was das Problem ist.

  

Der Versuch, frei stehendes Objekt zu beharren "jee.jpa2.Item-2".

Nachdem Sie Ihre Entity beharren auf der ersten Schleife, alle nachfolgenden Anrufe an em.persist (..) Sie übergeben tatsächlich in einem frei stehenden Entity (Keine neue Entity). Einstellen des ID-Feld auf NULL bedeutet nicht, dass die Entity jetzt neu ist.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top