下面是我的测试代码:

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

这是实体:

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

}

执行测试后出现错误:

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)

请解释一下这里发生了什么?

有帮助吗?

解决方案

为了严格回答问题标题,运行时增强是使用 javaagent 来完成的,该 javaagent 在使用 JDK 1.6 时可以动态加载(这记录在 实体增强).

关于您面临的问题,我怀疑它是一个 OpenJPA 错误(我见过几个 相似的 诸如此类的问题 OPENJPA-755),错误消息与您的代码不一致,因为您将主键字段设置为 null 并且没有任何版本字段。你应该报告一下。

话虽这么说,“解决”该问题的一个简单方法是创建一个新的 Item 循环内的实例。像这样的东西:

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

补充笔记:

你为何路过 System.getProperties() 创建时 EntityManagerFactory?

你应该关闭 EntityManagerFactory 测试结束时:

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

更新: 回答评论。来自 JPA 规范:

3.2 实体实例的生命周期

本节介绍了用于管理实体实例的生命周期的实体操作。实体实例可以被描述为新,管理,分离或删除。

  • A 新的 实体实例有 没有持久的身份, ,并且尚未与持久性上下文相关联。
  • A 管理 实体实例是一个具有持久身份的实例,当前与持久性上下文相关联。
  • A 超然的 实体实例是一个具有持久身份的实例 不(或不再)与持久性上下文相关联.
  • A 已删除 Entity实例是一个具有持久身份的实例,与持久性上下文相关联,该实例已计划从数据库中删除。

因此,如果您有一个独立的实体(即 不与持久上下文关联)并且如果您设置 Id 带注释的字段 null (因此它有 没有持久的身份),那么您就拥有了规范定义为新实体的内容,无论 OpenJPA 行为如何。这就是为什么我认为这是 OpenJPA 中的一个错误(而且错误消息无论如何都是不连贯的)。

其他提示

一点要注意,就是 “实体管理器跟踪通过Java对象引用的实体。”

我只能一次又一次在for循环持续相同的Java对象/参考当且仅当我移动emf = Persistence.createEntityManagerFactory("basicPU")语句在for循环。 像这样:

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

但是,如果for循环是这样的:

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

我得到EntityExistException。

这是否意味着谁是跟踪项目对象的emf.createEntityManager()方法返回的EntityManager的缓存副本中的for循环的前一次迭代坚持? 的一个BIG NO。 因为当我试图执行下面线..

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

它的印刷..

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

这意味着的 emf.createEntityManager()总是返回的EntityManager的新实例。

所以,清单1和清单2中,我总是得到新的EntityManager实例,并仍与清单1我能坚持同一个对象在数据库中,但清单2中,我得到EntityExistException。为什么会这样?

我想,如果我有两个房源新的EntityManager(1和2)我应该能够坚持同一个对象在数据库中,因为EntityManager的跟踪实体通过Java对象引用,并在每次迭代我有新的EntityManager,它不知道或者不应该知道的引用保存的对象/坚持在数据库上一次迭代通过其他EntityManager对象实例。

OpenJPA 2.0 在 JDK 1.6(不是 JRE)上运行时可以动态安装运行时增强器, 请参阅文档. 。从技术上讲,他们使用动态附加 java 代理 附加API, ,无需 -javaagent 选项。

所以 Item 类实际上得到了增强,并且实体管理器知道它正在保留一个独立的实例,尽管 null id 和实体管理器的关闭。

在错误消息告诉你问题是什么。

  

尝试坚持分离对象 “jee.jpa2.Item-2”。

在你坚持你的实体在第一循环中,所有的后续调用em.persist(..)你实际上是在传递一种超然的实体(不是新实体)。设置id字段为空并不意味着实体现在是新的。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top