简体   繁体   English

JPA EntityManager:“查找”与“ createQuery”和“ getResultList”

[英]JPA EntityManager: 'find' vs. 'createQuery' and 'getResultList'

I'm working on a legacy code base that uses JPA (not JPA-2), and have come across the following method in a DAO implementation class to retrieve a single entity by ID (which is also it's primary key): 我正在使用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);
    }

}

I now need to write a similar DAO class for a different entity, and my method to find the entity by it's primary key looks a lot simpler! 现在,我需要为不同的实体编写类似的DAO类,并且通过主键查找实体的方法看起来要简单得多! :

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

The original author is not around to ask, so I'm wondering if anyone can suggest reasons as to why he constructed a JPQL query rather than simply using EntityManager#find(Class<T> entityClass, Object primaryKey) ? 原始作者没有来问这个问题,所以我想知道是否有人可以提出他为何构造JPQL查询而不是简单地使用EntityManager#find(Class<T> entityClass, Object primaryKey)

The javadoc for the find method says: find方法的Javadoc说:

If the entity instance is contained in the persistence context, it is returned from there. 如果实体实例包含在持久性上下文中,则从那里返回它。

which suggests some form of caching and/or delayed writes. 这表明某种形式的缓存和/或延迟的写入。 The javadoc for the createQuery and getResultList methods don't say anything like this. createQuerygetResultList方法的Javadoc不会这样说。

I am unaware of any business or technical requirement in this application that would preclude caching, or of any issues resulting from stale entities or similar. 我没有意识到此应用程序中的任何业务或技术要求都将阻止缓存,也没有意识到由陈旧的实体或类似实体导致的任何问题。 I will check these with the rest of the project team when available, but I just thought I'd canvas the opinion of the SO community to see if there might be other reasons why a query was constructed and executed instead of simply using find 我将与项目团队的其他成员一起检查这些情况,但是我只是想以SO社区的意见为依据,查看是否还有其他原因构造和执行查询而不是简单地使用find来构建和执行查询。

(I've seen this: When use createQuery() and find() methods of EntityManager? . Whilst it answers the question re: difference between createQuery and find, it doesn't answer it in context of finding entities by primary key) (我已经看到了这一点: 当使用EntityManager的createQuery()和find()方法时吗?虽然它回答了以下问题:createQuery和find之间的区别,但是在通过主键查找实体的上下文中它没有回答)

Updated with additional info 更新了其他信息

From looking at the other methods in the original DAO class, it looks like there has been a deliberate/conscious decision to not take advantage of JPA managed objects. 通过查看原始DAO类中的其他方法,似乎已经有一个故意/有意识的决定,不利用JPA管理的对象。 As above, the method to find by primary key uses a JPQL query. 如上所述,按主键查找的方法使用JPQL查询。 The method to delete an entity also uses a JPQL query. 删除实体的方法还使用JPQL查询。 And the method to update an entity makes a copy of the passed in entity object and calls EntityManager#merge with the copy (thus the copy is a managed object, but is never used or returned from the method) 更新实体的方法将复制传入的实体对象,并使用该副本调用EntityManager#merge (因此,该副本是托管对象,但从不使用该方法或从该方法返回)
Weird .... 奇怪的 ....

Short answer, there is no difference between find and a select query. 简短的答案,查找和选择查询没有区别。

Your question suggests that you are not entirely familiar with what an EntityManager and a Persistence context is. 您的问题表明您并不完全了解EntityManager和Persistence上下文。 EntityManager implementation are not required to be thread safe. EntityManager实现不需要是线程安全的。 If the EntityManager is injected by Spring or and EJB-container it is thread safe (because it is a thread-local proxy), if it is application managed (you created it by calling EntityManagerFactory.createEntityManager(), it is not thread safe, and you can't stor it in a variable, but have to create a new one every time. 如果EntityManager是由Spring或EJB容器注入的,则它是线程安全的(因为它是线程本地代理),如果它是应用程序管理的(通过调用EntityManagerFactory.createEntityManager()创建的,则不是线程安全的),并且您不能将其存储在变量中,而每次都必须创建一个新变量。

The Persistence Context, is where entities live, whenever you create a new EntityManager you get a new Persistence context (there are exceptions to this rule). 持久性上下文是实体所在的位置,每当您创建新的EntityManager时,您都会获得一个新的持久性上下文(此规则有例外)。 When you persist an Entity, or load an existing entity from the db (using find or query) it will be managed by the persistence context. 当您持久化一个实体,或从数据库(使用查找或查询)加载现有实体时,它将由持久性上下文管理。 When you commit a transaction JPA runs through ALL Entities managed by the Persistence context, and checks the state of the entity to find out which queries should be sent to the database. 提交事务时,JPA会在Persistence上下文管理的所有实体中运行,并检查实体的状态以找出应将哪些查询发送到数据库。

The PersistenceContext can be seen as a first-level cache on top of the database. PersistenceContext可以看作是数据库顶部的一级缓存。 It is meant to have a short lifespan, typically no longer than the transaction. 这意味着使用寿命很短,通常不超过交易时间。 If you re-use the same entityManager for multiple transactions, the size could grow as more data is loaded, this is bad because every transaction has to run through all entities in the persistence context. 如果您将同一entityManager用于多个事务,则大小可能会随着加载更多数据而增长,这很糟糕,因为每个事务都必须在持久性上下文中遍历所有实体。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM