一位新同事刚刚建议在 Hibernate 中使用带有注释的命名 HQL 查询(即@NamedQuery),而不是在我们的 XxxxRepository 类中嵌入 HQL。
我想知道的是,除了集中查询之外,使用注释是否提供任何优势?
特别是,是否有一些性能增益,例如因为查询只在加载类时解析一次,而不是每次执行 Repository 方法时?
一位新同事刚刚建议在 Hibernate 中使用带有注释的命名 HQL 查询(即@NamedQuery),而不是在我们的 XxxxRepository 类中嵌入 HQL。
我想知道的是,除了集中查询之外,使用注释是否提供任何优势?
特别是,是否有一些性能增益,例如因为查询只在加载类时解析一次,而不是每次执行 Repository 方法时?
来自 Pro EJB 3 (Mike Keith):
“...我们尽可能推荐命名查询。作为应用程序部署或初始化阶段的一部分,持久性提供程序通常会采取措施将 JPQL 命名查询预编译为 SQL。”
尽管本书是关于 JPA 的,但一般建议适用于 Hibernate。但是,由于 Hibernate 缓存解析了 HQL/JPQL,因此您可能不会看到很大的性能提升。使用命名查询的另一个优点是它使您可以选择在部署时使用映射文件覆盖查询,而无需重新构建应用程序;如果您需要在生产中调整查询,这很有用。
除了任何可能的性能提升之外,我相信另一个优势是通过使用带有注释的 HQL 查询,您可以保护自己免受 SQL 注入攻击。
对于 Web 应用程序,如果查询包含任何用户输入数据,这很重要。
Lars 关于 SQL 注入的评论可能具有误导性,尽管我不认为这是他的意图,并且我想提供更多的上下文,这样评论就不会被误解。
确实,命名查询是按规范进行参数化的,使用命名参数是防范 SQL 注入的一步。但是,它并不能完全防止 SQL 注入(有关更多信息,请参阅他的链接)。评论的措辞表明,使用命名查询是防范注入攻击的唯一必要步骤。实际上,普通查询可以(并且应该)被参数化,并且将提供与命名查询完全相同的注入攻击隔离级别,并且参数化查询只是阻止注入攻击的许多必要步骤之一。
要添加到 Lars 关于 webapps 的评论,请注意,无论应用程序是否面向外部,或者输入数据是来自用户还是来自另一个数据库(甚至是相同的数据库),清理数据以防止注入攻击都很重要数据库)。
就个人而言,我认为性能提升不如在服务器启动期间解析您的 hql 查询这一事实重要,如果您的 hql 查询错误,则为您提供即时消息。
我更喜欢在测试之前而不是在测试期间捕获这些错误。
上次,在测试期间,我在代码中遇到了一个查询,由于 CaSiNg,该查询不起作用,实际上从未起作用。当使用命名查询时,这在服务器启动期间会立即变得明显。
而且,当然,我不喜欢将 HQL 与 Java 代码混在一起。