3.4.4.4. 执行 JPQL 查询

本章节介绍 Query 接口,该接口用于在 ORM 级别执行 JPQL 查询。可以通过调用 createQuery() 方法从当前的 EntityManager 实例获得其引用。如果查询语句用于加载实体,建议使用结果类型作为参数调用 createQuery()。这将创建一个 TypedQuery 实例。

Query 的方法主要对应于标准 JPA javax.persistence.Query 接口的方法。我们了解下之间的差异。

  • setView()addView() – 定义用于加载数据的视图

  • getDelegate() – 返回由 ORM 实现提供的 javax.persistence.Query 实例。

如果为查询指定了视图 ,则默认情况下查询使用 FlushModeType.AUTO 模式,这会影响当前持久化上下文包含已更改实体实例的情况:这些实例将在执行查询之前保存到数据库中。换句话说,ORM 首先同步持久化上下文和数据库中的实体状态,之后才执行查询。这样可以保证查询结果包含所有相关实例,即使它们尚未明确地保存到数据库中。这样做的缺点是会有一个隐式刷新(flush),也就是为所有当前已更改的实体实例执行 SQL 更新语句,这可能会影响性能。

如果在没有视图的情况下执行查询,则默认情况下查询使用 FlushModeType.COMMIT 模式,这意味着查询不会导致刷新(flush),并且查询结果将不会体现出当前持久化上下文数据。

在大多数情况下,忽略当前的持久化上下文是可以接受的,并且是首选行为,因为它不会导致额外的 SQL 更新。但是在使用视图时存在以下问题:如果持久化上下文中存在已更改的实体实例,并且使用视图以 FlushModeType.COMMIT 模式执行查询去加载相同的实例,则更改将丢失。这就是在运行带有视图的查询时默认使用 FlushModeType.AUTO 的原因。

还可以使用 Query 接口的 setFlushMode() 方法显式设置刷新(flush)模式,这样将覆盖上述默认设置。

对软删除的实体使用 DELETE FROM 语句

如果开启了软删除模式,然后对已经软删除的实体执行 DELETE FROM 的 JPQL 语句的话会抛出异常。这种语句在翻译成 SQL 时,会删除所有没有标记删除的数据。这种不好理解的行为默认是关闭的,可以通过 cuba.enableDeleteStatementInSoftDeleteMode 应用程序属性开启。

查询提示

使用 Query.setHint() 方法可以为生成的 SQL 语句添加 hints - 提示。提示通常用来设置查询语句应如何使用索引或其它数据库特性。框架定义了下面这些常量,可以用来传递给该方法作为提示名称:

  • QueryHints.SQL_HINT - 提示的值添加在生成的 SQL 语句后面。这里需要提供全部的提示字符串,也包括注释分隔符。

  • QueryHints.MSSQL_RECOMPILE_HINT - 为 MS SQL Server 数据库添加 OPTION(RECOMPILE) SQL 提示。提示的值会被忽略。

当使用DataManager的时候,查询提示可以使用 LoadContext.setHint() 方法添加。