JPA:如果 EntityManager 关闭,为什么加载惰性字段
JPA: why lazy fields are loaded if EntityManager is closed
我使用 eclipselink 并有以下代码:
public Temp getTemp() {
EntityManager em=emf.createEntityManager();
String queryString="SELECT a FROM Temp a";
EntityGraph<Temp> eg = em.createEntityGraph(Temp.class);
eg.addAttributeNodes("id");
//eg.addAttributeNodes("name");
Query query = em.createQuery(queryString);
query.setHint("javax.persistence.fetchgraph", eg);
List<Temp> items=query.getResultList();
em.close();// ENTITYMANAGER IS CLOSED
return items.get(0);
}
public void temp(){
Temp temp=getTemp();
System.out.println("id:"+temp.getId());
System.out.println("name:"+temp.getName());
}
正如您从代码中看到的,我们只加载了 id。但是,当我们执行 temp.getName() 时,会执行一个 SQL 查询并加载必要的数据。为什么?我们确实关闭了实体管理器。我希望在 temp.getName().
处得到异常
编辑 1
经过一些研究,我发现了以下内容——当编织是静态的(<property name="eclipselink.weaving" value="static"/>
+ de.empulse.eclipselink
编织插件)时,我上面描述的行为是真实的。然而,当编织是动态的(<property name="eclipselink.weaving" value="true"/>
)时,我得到异常:
java.lang.ClassNotFoundException: org.eclipse.persistence.internal.jpa.EntityManagerImpl not found by com.temp [57]
at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1574)
at org.apache.felix.framework.BundleWiringImpl.access0(BundleWiringImpl.java:79)
at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:2018)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at com.temp.Temp._persistence_checkFetched(Temp2.java)
at com.temp.Temp._persistence_get_name(Temp2.java)
at com.temp.Temp.getName(Temp.java:44)
所以问题移到这里:Eclipselink: Difference between static and dynamic weaving
因为那是 EclipseLink 并且它支持字段的分离加载...即不在 JPA 规范中并且完全不可移植的东西(即在其他实现中不支持)。它的 "detached" 状态并不是真正的 "detached",并且与 EntityManagerFactory 保持联系。如果你关闭 EMF,它们就会变成真正的 "detached".
参见this email chain discussing the "feature"。它没有提到关闭它的方法(这样你就可以有便携的行为),而且实际上要求这个人提出请求!关于为什么 JPA TCK 不检查可移植行为的问题是一个要问 Oracle 的问题……但是等一下,EclipseLink 团队写了 TCK 不是吗……嗯……
为了保持可移植性,您将按照 JPA 规范进行分离,而不依赖于此类行为
我使用 eclipselink 并有以下代码:
public Temp getTemp() {
EntityManager em=emf.createEntityManager();
String queryString="SELECT a FROM Temp a";
EntityGraph<Temp> eg = em.createEntityGraph(Temp.class);
eg.addAttributeNodes("id");
//eg.addAttributeNodes("name");
Query query = em.createQuery(queryString);
query.setHint("javax.persistence.fetchgraph", eg);
List<Temp> items=query.getResultList();
em.close();// ENTITYMANAGER IS CLOSED
return items.get(0);
}
public void temp(){
Temp temp=getTemp();
System.out.println("id:"+temp.getId());
System.out.println("name:"+temp.getName());
}
正如您从代码中看到的,我们只加载了 id。但是,当我们执行 temp.getName() 时,会执行一个 SQL 查询并加载必要的数据。为什么?我们确实关闭了实体管理器。我希望在 temp.getName().
处得到异常编辑 1
经过一些研究,我发现了以下内容——当编织是静态的(<property name="eclipselink.weaving" value="static"/>
+ de.empulse.eclipselink
编织插件)时,我上面描述的行为是真实的。然而,当编织是动态的(<property name="eclipselink.weaving" value="true"/>
)时,我得到异常:
java.lang.ClassNotFoundException: org.eclipse.persistence.internal.jpa.EntityManagerImpl not found by com.temp [57]
at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1574)
at org.apache.felix.framework.BundleWiringImpl.access0(BundleWiringImpl.java:79)
at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:2018)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at com.temp.Temp._persistence_checkFetched(Temp2.java)
at com.temp.Temp._persistence_get_name(Temp2.java)
at com.temp.Temp.getName(Temp.java:44)
所以问题移到这里:Eclipselink: Difference between static and dynamic weaving
因为那是 EclipseLink 并且它支持字段的分离加载...即不在 JPA 规范中并且完全不可移植的东西(即在其他实现中不支持)。它的 "detached" 状态并不是真正的 "detached",并且与 EntityManagerFactory 保持联系。如果你关闭 EMF,它们就会变成真正的 "detached".
参见this email chain discussing the "feature"。它没有提到关闭它的方法(这样你就可以有便携的行为),而且实际上要求这个人提出请求!关于为什么 JPA TCK 不检查可移植行为的问题是一个要问 Oracle 的问题……但是等一下,EclipseLink 团队写了 TCK 不是吗……嗯……
为了保持可移植性,您将按照 JPA 规范进行分离,而不依赖于此类行为