[英]JPA EntityManager: 'find' vs. 'createQuery' and 'getResultList'
我正在使用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);
}
}
现在,我需要为不同的实体编写类似的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说:
如果实体实例包含在持久性上下文中,则从那里返回它。
这表明某种形式的缓存和/或延迟的写入。 createQuery
和getResultList
方法的Javadoc不会这样说。
我没有意识到此应用程序中的任何业务或技术要求都将阻止缓存,也没有意识到由陈旧的实体或类似实体导致的任何问题。 我将与项目团队的其他成员一起检查这些情况,但是我只是想以SO社区的意见为依据,查看是否还有其他原因构造和执行查询而不是简单地使用find
来构建和执行查询。
(我已经看到了这一点: 当使用EntityManager的createQuery()和find()方法时吗?虽然它回答了以下问题:createQuery和find之间的区别,但是在通过主键查找实体的上下文中它没有回答)
通过查看原始DAO类中的其他方法,似乎已经有一个故意/有意识的决定,不利用JPA管理的对象。 如上所述,按主键查找的方法使用JPQL查询。 删除实体的方法还使用JPQL查询。 更新实体的方法将复制传入的实体对象,并使用该副本调用EntityManager#merge
(因此,该副本是托管对象,但从不使用该方法或从该方法返回)
奇怪的 ....
简短的答案,查找和选择查询没有区别。
您的问题表明您并不完全了解EntityManager和Persistence上下文。 EntityManager实现不需要是线程安全的。 如果EntityManager是由Spring或EJB容器注入的,则它是线程安全的(因为它是线程本地代理),如果它是应用程序管理的(通过调用EntityManagerFactory.createEntityManager()创建的,则不是线程安全的),并且您不能将其存储在变量中,而每次都必须创建一个新变量。
持久性上下文是实体所在的位置,每当您创建新的EntityManager时,您都会获得一个新的持久性上下文(此规则有例外)。 当您持久化一个实体,或从数据库(使用查找或查询)加载现有实体时,它将由持久性上下文管理。 提交事务时,JPA会在Persistence上下文管理的所有实体中运行,并检查实体的状态以找出应将哪些查询发送到数据库。
PersistenceContext可以看作是数据库顶部的一级缓存。 这意味着使用寿命很短,通常不超过交易时间。 如果您将同一entityManager用于多个事务,则大小可能会随着加载更多数据而增长,这很糟糕,因为每个事务都必须在持久性上下文中遍历所有实体。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.