JPA EntityManager:'找到'与' createQuery'和' getResultList'

时间:2016-12-13 12:14:28

标签: java entity-framework hibernate jpa

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

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

}

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

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

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

find方法的javadoc说:

  

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

表示某种形式的缓存和/或延迟写入。 createQuerygetResultList方法的javadoc不会说出这样的内容。

我不知道此应用程序中的任何业务或技术要求会阻止缓存,或者由陈旧实体或类似事件导致的任何问题。我会在可用时与项目团队的其他成员一起检查这些内容,但我只是想我画出SO社区的意见,看看是否有其他原因构建和执行查询而不是简单地使用{ {1}}

(我已经看到了这一点:When use createQuery() and find() methods of EntityManager?。虽然它回答了问题:createQuery和find之间的区别,但它并没有在按主键查找实体的情况下回答它)

更新了附加信息

通过查看原始DAO类中的其他方法,看起来有意识/有意识地决定不利用JPA管理对象。如上所述,通过主键查找的方法使用JPQL查询。删除实体的方法也使用JPQL查询。更新实体的方法会复制传入的实体对象并使用副本调用find(因此副本是一个托管对象,但从不使用或从方法返回)
奇怪......

1 个答案:

答案 0 :(得分:4)

简短回答,find和select查询之间没有区别。

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

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

PersistenceContext可以看作是数据库顶层的第一级缓存。它意味着寿命短,通常不超过交易。如果为多个事务重用相同的entityManager,则大小会随着更多数据的加载而增长,这很糟糕,因为每个事务都必须在持久化上下文中运行所有实体。