【问题标题】:Is it good practice to use @NamedQuery for single column selects (J2EE/JPA, Hibernate)将@NamedQuery 用于单列选择(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();

【问题讨论】:

    标签: hibernate jakarta-ee jpa named-query


    【解决方案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 的大讨论:stackoverflow.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。
    猜你喜欢
    • 2013-03-28
    • 2023-04-07
    • 2019-05-27
    • 1970-01-01
    • 2013-07-02
    • 1970-01-01
    • 2019-03-06
    • 2013-03-30
    • 2015-09-02
    相关资源
    最近更新 更多