JPA查询语言(5)

排序(ORDER BY)

ORDER BY

允许你对查询结果进行排序。数据库排序比应用程序更有效。要依据集合的顺序,可以使用

ORDER BY

操作符。(更多信息参见第三章Entities Part II中

@OrderBy

注释)

这是一个JPQL查询语句中

Order By

操作符的所在位置。

select from [where] [group by] [having] [order by]

Order By

的语法为:

ORDER BY expression [ASC | DESC] {, expression [ASC | DESC]}*

下面是一些合法的

Order By

实例。

  • SELECT u FROM User u ORDER BY u

  • SELECT u FROM User u ORDER BY u.address

  • SELECT u.username, u.id FROM User u ORDER BY u.username DESC

expression

可以是一个标识符号变量,一个单值关联路径,一个状态字段路径表达式。这些查询语句一一演示了

Order By

的这些类型。

你必须注意使用

Order By

操作符的一些限制。

  • 当使用一个标识符号变量,一个单值关联字段时,你用来对查询进行排序的项目必须是一个可排序的类型,例如数字类型,字符串,字符类型,或是时间日期。

  • 如果你使用一个状态字段路径表达式,同时它也必须出现在

    SELECT

    语句中。

ASC

表示升序(由小到大),是默认的排序方式。

DESC

表示降序排列(由大到小),使用时显式在查询的

Order By

语句上添加它。排序的优先级是按罗列的字段从左到右的顺序进行。

不难理解,下面的查询是不合法的,因为它对一个字段进行排序但它却不在

SELECT

语句中。

SELECT u.username, u.id FROM User u ORDER BY u.password

JPQL提供了一种替代方案,用一条语句更新或删除一个或多个实体。JPQL中批处理支持一次可以处理一个实体类型(和它的子类)。也就是说,你只能在

FROM

UPDATE

指定唯一实体。这里是一个

UPDATE

查询的语法。

UPDATE abstract_persistence_scheama_name [AS] identification_variable

SET state_field | single_value_association_field = value

{,state_field | single_value_association_field = value }*

value

引用必须与你要更新的状态字段或是单值关联字段的类型相同。你可以将下列任意值用于

value

  • 一个算术表达式

  • 字符串

  • 时间日期(datetime)

  • 布尔值(boolean)

  • 枚举类型(enum)

  • 简单实体表达式

  • NULL

DELETE

语句看起来如下。

DELETE FROM abstract_persistence_scheama_name [[AS] identification_variable]

[WHERE clause]

WHERE

语句的语法与

SELECT

相同(更多信息参见

SELECT

语句一节)。

DELETE

操作符只影响

FROM

语句指定的实体及其子类。此操作不会级联到任何相关的实体。此外,

UPDATE

操作符不更新实体的version一列。

批处理操作最终转换成SQL并在数据库中执行,绕过了持久化环境(persistence context)。当使用一个事务作用域(transaction-scoped)的持久化环境,会在它们所在事务内执行或在一个事务开始时执行。

批量操作和扩展的持久化环境(extended persistence context)的组合在管理上有所不同。因为一个扩展持久化环境不会与数据库同步,直到参与到一个事务中去,你可以有一些实体已经删除了,但仍可能存在于持久化环境中。

持久化实现通常会在执行批处理操作前禁用一些缓存功能。基于不同的实现,部分或全部缓存功能会被禁用。频繁的使用批处理操作会影响应用程序的性能。基于这些原因,你应该在它们自己的事务内或是一个事务开始时执行批处理操作。

当你使用一个

UPDATE

或是

DELETE

查询时,你一定会用到Query API提供的方法--

executeUpdate()

,来执行更新或是删除操作。如果你使用

getResultList()

getSingleResult()

,持久化实现会抛出一个

IllegalStateException

异常。同样,你用

executeUpdate()

来执行一个

SELECT

查询,持久化实现会抛出一个

IllegalStateException

异常。

下面是一些批量更新的例子。

  • 一个论坛帖子数量的两倍。

    Query q2 = em.createQuery("UPDATE Forum AS f "

    +"SET f.forumPostCount = f.forumPostCount * 2");

    q2.executeUpdate();

  • 将所有的

    Role

    实体的

    dateUpdated

    字段设置为当前日期和时间。

    Query q = em.createQuery("UPDATE Role AS r " +

    "SET r.dateUpdated = CURRENT_TIMESTAMP");

    q.executeUpdate();

  • 将布尔字(

    pruningEnabled)

    )段值设置为

    true

    。在

    agoraBB

    应用程序中,用

    EntityListener

    类来设置

    dateUpdated

    updatedByUser

    字段。version字段是由持久化实现进行管理。避开这些弯弯角角,当你执行批量操作时,你的查询写成更新字段。还有,要注意的是,

    executeUpdate

    返回实体更新的数目(删除时返回删除的数量)。

    // Assume we already fetched the correct User identified by

    // the variable adminUser

    Query forumUpdate = em.createQuery("UPDATE Forum AS f " +

    "SET f.pruningEnabled = TRUE, f.dateUpdated = CURRENT_TIMESTAMP, " +

    "f.version = f.version + 1, f.updatedByUser = :user");

    forumUpdate.setParameter("user", adminUser);

    int entitiesUpdated = forumUpdate.executeUpdate();

    你可以将

    pruningEnabled

    的值设置为

    null

    ,将其进行重位。如下所示。

    Query pruningReset = em.createQuery("UPDATE Forum AS f " +

    "SET f.pruningEnabled = NULL");

    pruningReset.executeUpdate();

    这条查询设置了

    enum

    类型的字段值。你必须使用

    enum

    类的长限定词,因为

    enum

    不是实体,持久化实现不法获得Status的信息,但它可以识别

    com.sourcebeat.jpa.model.Status

    Query enumUpdate = em.createQuery("UPDATE Forum AS f " +

    "SET f.status = com.sourcebeat.jpa.model.Status.LOCKED " +

    "WHERE f.type = com.sourcebeat.jpa.model.FTPType.ANNONUCEMENT");

    int enumUpdateCount = enumUpdate.executeUpdate();

这里有几个

DELETE

操作的例子。

  • 删除系统中所有无密码的用户(

    Users

    )。

    Query removeRoles = em.createQuery("DELETE FROM User u " +

    "WHERE u.password = NULL");

    int rolesRemoved = removeRoles.executeUpdate();

  • 删除没有主题(

    Topics

    )的论坛(

    Forum

    )。

    Query removeForums = em.createQuery("DELETE FROM Forum f " +

    "WHERE f.topics IS EMPTY");

    int forumsRemoved = removeForums.executeUpdate();

JPQL提供了大量实体查询,分组,排序和总结的功能。包括丰富的关联(join)操作支持和即时读取延迟关联关系(eagerly fetch lazy relationship)的能力。你已经学习所支持的各种函数和表达式,以及

SELECT

语句所能提供的各种选项。本章最后探讨了批量处理操作,它具备使用单条查询语句(实际是指

UPDATE

DELETE

语句)影响一个或多个实体的能力。

现在你应该很熟悉了JPQL所能提供的丰富的功能,利用它,从简单到复杂一步步地创建自己的查询。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值