1

我在我的 Java ee 应用程序中使用 JPA。我有一个映射到类 A 的表 A。现在,当我查询实体(例如,通过它的 id)时,它总是返回一个不同的对象。例子:

public A getAById(int id) {
    A obj = (A) em.createNamedQuery("getAById")
            .setParameter("id", id).getSingleResult();
    return obj;
}

public void test(){
    getAById(1)==getAById(1) //is false
}

有没有办法告诉 JPA 在从数据库查询时不要总是创建新实例,而是在已经查询到现有对象时返回它?

//编辑这篇文章对我帮助很大: http ://en.wikibooks.org/wiki/Java_Persistence/Caching#Example_JPA_2.0_Cacheable_annotation

4

3 回答 3

3

有没有办法告诉 JPA 在从数据库查询时不要总是创建新实例,而是在已经查询到现有对象时返回它?

JPA 从不为选择查询创建新实体。请参阅以下示例

Query qry = em.createNamedQuery("SELECT r FROM BusinessUnit r WHERE r.buKey = :buKey");
Object result1 = qry.setParameter("buKey", "32").getSingleResult();
qry = em.createNamedQuery("SELECT r FROM BusinessUnit r WHERE r.buKey = :buKey");
Object result2 = qry.setParameter("buKey", "32").getSingleResult();
System.out.println(result1 == result2);

对于上述情况,我是result1 == result2真的,因为hashCode方法在实体类中被覆盖。

如果您的实体类被方法覆盖equals,您可以使用equals方法进行测试,而不是与对象引用进行比较。

public void test(){
    getAById(1).equals(getAById(1)) ;
}
于 2013-02-06T12:18:42.040 回答
2

JavaEE 容器将 JPA 提供者 EntityManager 包装在一个代理中,因此您看到的行为很可能是因为您的容器在事务之外获得了一个新的 EM。您的两个 getAById(1) 调用将转到两个不同的实体管理器。您可以通过将它们包装在单个事务中来解决此问题,强制容器在事务的生命周期内使用相同的实体管理器。

于 2013-02-06T13:14:49.910 回答
-2

如果持久化上下文中已经存在实体实例,是的,但是您需要使用EntityManager操作,例如entityManager.find(entity.class, id);这样做将要求entitymanager首先从关联的PersistenceContext中查找实体,如果找不到它将从 DB 中查询。一旦实体实例第一次加载到关联的 PersistenceContext 中,针对相同实体 ID 的其余查询将不会触发 DB 查询,并且始终重用缓存在 PersistenceContext 中的查询。这是 JPA 一级缓存。

使用JPQL将不符合您的要求,因为JPQL将绕过PersistenceContext并始终直接与 DB 通信,这最终会得到不同的 java 对象(就主键而言是相同的实体)。

于 2013-02-06T12:17:26.727 回答