以下是我的测试代码:
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)
请解释这里发生的事情?
答案 0 :(得分:1)
要严格回答这个问题标题,运行时的增强是使用可使用JDK 1.6时被动态加载的javaagent完成(这在记录Entity Enhancement)。
对于您所遇到的问题,我怀疑这是一个错误的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实体实例的生命周期
本节介绍 用于管理的EntityManager操作 实体实例的生命周期。一个 可以表征实体实例 作为新的,管理的,分离的,或 除去。
- 新实体实例没有持久身份,现在还没有 与持久化上下文相关联。
- 托管实体实例是具有持久标识的实例 目前与a相关联 持久性上下文。
- 分离的实体实例是具有持久标识的实例 那是没有(或不再)关联 持久化背景。
- 已删除实体实例是具有持久标识的实例, 与持久化上下文相关联, 计划从中删除 数据库中。
因此,如果你有一个分离的实体(即由此的不与持久性上下文相关联的强>),并如果设置了Id
注释字段来null
(它具有这样没有持久性身份),无论OpenJPA行为如何,您都具有规范定义为NEW实体的确切内容。这就是为什么我认为这是OpenJPA中的一个错误(错误信息无论如何都是不连贯的)。
答案 1 :(得分:1)
请注意,“实体管理器通过Java对象引用跟踪实体。”
当且仅当我在for循环中移动emf = Persistence.createEntityManagerFactory("basicPU")
语句时,我才能在for循环中一次又一次地持久保存相同的java对象/引用。
像这样:
清单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循环的前一次迭代中持久存在的item对象。 一个大号 因为当我试图执行下面的行..
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。为什么这样?
我认为如果我在两个清单(1和2)中都有新的EntityManager,我应该能够在数据库中保留相同的对象,因为EntityManager通过java对象引用跟踪实体,并且在每次迭代中我都有新的EntityManager,它不知道或者不应该知道其他EntityManager对象实例在上一次迭代中保存/保存在数据库中的对象引用。
答案 2 :(得分:0)
您是否看过源代码?它深入内核:
第2563行
答案 3 :(得分:0)
OpenJPA 2.0可以在JDK 1.6(而不是JRE)see docs上运行时动态安装运行时增强器。从技术上讲,它们使用Attach API动态附加java代理,而不需要-javaagent
选项。
因此,Item
类实际上已得到增强,并且实体管理器知道它仍然存在一个分离的实例,尽管null
id和关闭实体管理器。
答案 4 :(得分:0)
错误消息告诉您问题所在。
尝试保留分离的对象“jee.jpa2.Item-2”。
在第一个循环中持久保存实体后,对em.persist(..)的所有后续调用实际上都是在一个分离的实体(不是新实体)中传递。将id字段设置为NULL并不意味着实体现在是新的。