JPA EntityManager:“find”与“createQuery”和“getResultList”

Nat*_*ell 0 java entity-framework hibernate jpa

我正在处理使用 JPA(不是 JPA-2)的遗留代码库,并且在 DAO 实现类中遇到了以下方法来通过 ID(这也是它的主键)检索单个实体:

public EmailTemplate findEmailTemplateById(long id) {

    LOG.debug("Entering findEmailTemplateById(id='" + id + "')");
    // Construct JPQL query       
    String queryString = "SELECT a FROM EmailTemplate a " +
            "WHERE templateId = :templateId";
    Query query = entityManager.createQuery(queryString);

    query.setParameter("templateId", id);

    LOG.debug("Using query " + queryString);

    List<EmailTemplate> resultList = query.getResultList();

    LOG.debug("Exiting findEmailTemplateByName(id='" + id + "') results size " + resultList.size() + " ( returns null if 0 )");

    if (resultList.isEmpty() || resultList.size() == 0) {
        return null;
    } else {
        return resultList.get(0);
    }

}
Run Code Online (Sandbox Code Playgroud)

我现在需要为不同的实体编写一个类似的 DAO 类,我通过主键查找实体的方法看起来简单多了!:

@Override
public EmailTemplateEdit findEmailTemplateEditById(long id) {
    LOG.debug("Entering findEmailTemplateEditById(id={})", id);
    return entityManager.find(EmailTemplateEdit.class, id);
}
Run Code Online (Sandbox Code Playgroud)

原作者不在身边,所以我想知道是否有人可以就他为什么构建 JPQL 查询而不是简单地使用EntityManager#find(Class<T> entityClass, Object primaryKey)?

find方法的 javadoc说:

如果实体实例包含在持久性上下文中,则从那里返回。

这表明某种形式的缓存和/或延迟写入。createQuerygetResultList方法的 javadoc没有这样说。

我不知道此应用程序中的任何业务或技术要求会妨碍缓存,也不知道由陈旧实体或类似实体引起的任何问题。我会在可用的时候与项目团队的其他成员一起检查这些,但我只是想我会征求 SO 社区的意见,看看是否还有其他原因可以构造和执行查询,而不是简单地使用find

(我已经看到了:When use createQuery() and find() methods of EntityManager?。虽然它回答了这个问题:createQuery 和 find 之间的区别,但它没有在通过主键查找实体的上下文中回答它)

更新了附加信息

从查看原始 DAO 类中的其他方法来看,似乎是有意/有意识地决定不利用 JPA 托管对象。如上,按主键查找的方法使用 JPQL 查询。删除实体的方法也使用 JPQL 查询。并更新实体的方法使得在实体对象,并呼吁通过副本EntityManager#merge与副本(因而副本是管理对象,但从未使用过或从方法返回)
怪异....

Kla*_*aek 6

简短的回答,查找和选择查询之间没有区别。

您的问题表明您并不完全熟悉 EntityManager 和 Persistence 上下文是什么。EntityManager 实现不需要是线程安全的。如果 EntityManager 是由 Spring 或 EJB 容器注入的,则它是线程安全的(因为它是线程本地代理),如果它是应用程序管理的(您通过调用 EntityManagerFactory.createEntityManager() 创建的,则它不是线程安全的,并且您不能将其存储在变量中,而必须每次都创建一个新变量。

Persistence Context 是实体所在的地方,每当您创建新的 EntityManager 时,您都会获得一个新的 Persistence 上下文(此规则有例外)。当您持久化实体或从数据库加载现有实体(使用查找或查询)时,它将由持久化上下文管理。当您提交事务时,JPA 会运行由 Persistence 上下文管理的所有实体,并检查实体的状态以找出应将哪些查询发送到数据库。

PersistenceContext 可以看作是数据库顶部的一级缓存。它的生命周期很短,通常不长于事务。如果您对多个事务重复使用相同的 entityManager,则大小可能会随着加载更多数据而增长,这很糟糕,因为每个事务都必须通过持久化上下文中的所有实体运行。