将@NamedQuery 用于单列选择(J2EE/JPA、Hibernate)是一种好习惯吗?
Posted
技术标签:
【中文标题】将@NamedQuery 用于单列选择(J2EE/JPA、Hibernate)是一种好习惯吗?【英文标题】:Is it good practice to use @NamedQuery for single column selects (J2EE/JPA, Hibernate) 【发布时间】:2011-12-18 22:16:47 【问题描述】:我正在开发使用 Hibernate 作为其持久性提供程序的 J2EE 6 代码库。我的经验更多是在 Spring 中,我对 JPA 注释和类似的东西还很陌生,但是我注意到所有实体类中都有很多这样的东西,这让我感到惊讶——我认为 @NamedQuery 更适合复杂的 SQL?确定这些简单的选择(以及在休眠映射中定义的连接)可以在不写出 SQL 的情况下完成吗?
In the Entity:
@NamedQueries(
@NamedQuery(name = "DealRaw.findByrawUrl", query = "SELECT d FROM DealRaw d WHERE d.rawUrl = :rawUrl"),
@NamedQuery(name = "DealRaw.findByState", query = "SELECT d FROM DealRaw d WHERE d.state = :state"),
.... etc ....
)
然后
In the Service Class
Query qR=_em.createNamedQuery("DealRaw.findByrawUrl"); //_em is an EntityManager
qR.setParameter("rawUrl", value);
List<DealRaw> dRs=(List <DealRaw>)qR.getResultList();
【问题讨论】:
【参考方案1】:这些查询不是 SQL 查询,而是 JPQL 查询。您可以将任何类型的查询放在命名查询中,无论是否复杂。
它们都有相同的优点:
JPA 引擎在启动时解析并验证查询,并可能缓存解析结果,以避免一次又一次地解析。 可以在代码中的多个位置轻松使用相同的查询(尽管这样的设计有问题)它们都有相同的缺点,IMO:查询没有定义在哪里使用,因此代码更难理解。
无论这些查询是否被命名,您都必须编写这些查询来执行它们。加载实体的唯一其他方法是使用它们的 ID 找到它们(这里不是这种情况),或者使用关联从一个实体导航到另一个实体(也不是这种情况)。
【讨论】:
谢谢,很好的解释。 NamedQueries 是否仅适用于使用 @Entity 注释的类?鉴于您的回答,我想将一些更复杂的、在 DAO 中打到多个表的那些 AFAIK,它们只能是 puton 实体和映射的超类【参考方案2】:为什么不使用 Criteria 而不是 NamedQuery?过滤会容易很多。在某些情况下,创建标准会变得非常混乱和困难,但是对于单列,我认为这是最简单的选择。
【讨论】:
好奇 Criteria 比 NamedQuery 有什么优势? 条件是类型安全的 NamedQuery 只是预先做出的选择,所以它们不是。 正如 JB Nizet 所说,NamedQuery 在启动时被解析,因此如果您运行任何单元测试,您将很快知道您的查询是否有问题。此外,像 STS 这样体面的 IDE 会在您编写查询时提醒您查询中的问题。不要误会我的意思,我相信命名查询和标准都有有效的用途。我发现在创建任何复杂的条件查询时,我必须先编写常规查询,然后将其转换为条件查询才能通过它。 列出猫 = sess.createCriteria(Cat.class).add(Restrictions.like("name", "Fritz%") ).list(); Hibernate 文档中的一个示例。 至于优势,这里有一个关于 HQL vs Criteria 的大讨论:***.com/questions/197474/hibernate-criteria-vs-hql 我想说这更取决于您的需求。对于复杂的查询,HQL 要好很多。【参考方案3】:正如 JB Nizet 所说,为了找到结果集,您必须在某处编写查询。
将它们用作 NamedQuery(或 CriteriaQuery,如果您愿意的话)的一个好处是您可以保护自己免受 SQL 注入。如果查询是在代码中使用字符串连接(例如String query = "SELECT d FROM DealRaw d WHERE d.rawUrl = '" + rawUrl + "'";
)动态创建的,或者甚至使用命名参数,将来的一些程序员可能会出现并以允许 SQL 注入的方式修改查询(如示例中所示) .
是的,有一些方法可以在使用串联代码构造的查询中使用命名参数,但这并不能像预定义的命名查询那样保护您。
【讨论】:
谢谢,我对 SQL 注入预防非常熟悉。我假设 NamedQueries 最终会变成 PreparedStatements? 所有查询最终都是准备好的语句,AFAIK。以上是关于将@NamedQuery 用于单列选择(J2EE/JPA、Hibernate)是一种好习惯吗?的主要内容,如果未能解决你的问题,请参考以下文章
NamedQuery:外部化实体后的 IllegalArgumentException(未找到查询)
NHibernate,如何读取 NamedQuery 结果元数据?
在@NamedQuery (JPA QL 1.0) 中设置为空的参数