5.3.8. 修改查询

5.3.8. 修改查询

5.3.8. Modifying Queries

前面的章节都描述了如何声明查询,来得到一个指定的实体或者实体集合。你可以使用“Spring Data库的自定义实现”中描述的工具,来添加一个自定义的修改行为。此方法对于大多数自定义功能都可用,你只需要通过@Modifying注解查询方法并绑定参数,就可以修改查询,如下例所示:

All the previous sections describe how to declare queries to access a given entity or collection of entities. You can add custom modifying behavior by using the facilities described in “Custom Implementations for Spring Data Repositories”. As this approach is feasible for comprehensive custom functionality, you can modify queries that only need parameter binding by annotating the query method with @Modifying, as shown in the following example:

例64. 声明操作查询

Example 64. Declaring manipulating queries

@Modifying
@Query("update User u set u.firstname = ?1 where u.lastname = ?2")
int setFixedFirstnameFor(String firstname, String lastname);

这样做会触发方法注解的查询,此时会做更新操作。在执行修改查询后,EntityManager可能包含过期的实体,我们不会自动清除(参考EntityManager.clear()JavaDoc获取更多信息),因为实际清除所有未清空的变更都在EntityManager中等待。如果你希望EntityManager自动清除,可以设置@Modifying注解的clearAutomatically属性为true

Doing so triggers the query annotated to the method as an updating query instead of a selecting one. As the EntityManager might contain outdated entities after the execution of the modifying query, we do not automatically clear it (see the JavaDoc of EntityManager.clear() for details), since this effectively drops all non-flushed changes still pending in the EntityManager. If you wish the EntityManager to be cleared automatically, you can set the @Modifying annotation’s clearAutomatically attribute to true.

衍生的删除查询

Derived Delete Queries

Spring Data JPA同样支持衍生的删除查询,让你可以不用去准确声明JPQL查询,如下例所示:

Spring Data JPA also supports derived delete queries that let you avoid having to declare the JPQL query explicitly, as shown in the following example:

例65. 使用一个衍生的删除查询

Example 65. Using a derived delete query

interface UserRepository extends Repository<User, Long> {

  void deleteByRoleId(long roleId);

  @Modifying
  @Query("delete from User u where user.role.id = ?1")
  void deleteInBulkByRoleId(long roleId);
}

虽然看起来deleteByRoleId(…)方法基本与deleteInBulkByRoleId(…)一样,但就两个方法执行来说,两个方法声明是一个重要的区别。作为命名建议,后一个方法针对数据库发布了一个单JPQL查询(在注解中定义的)。意味着甚至当前加载的User实例都没有看见被调用的生命周期回调。

Although the deleteByRoleId(…) method looks like it basically produces the same result as the deleteInBulkByRoleId(…), there is an important difference between the two method declarations in terms of the way they get executed. As the name suggests, the latter method issues a single JPQL query (the one defined in the annotation) against the database. This means even currently loaded instances of User do not see lifecycle callbacks invoked.

为了确保生命周期查询被实际调用,deleteByRoleId(…)的一次调用执行了一次查询,并逐个删除返回的实例,所以持久化提供器可以在那些实体上实际调用@PreRemove回调。

To make sure lifecycle queries are actually invoked, an invocation of deleteByRoleId(…) executes a query and then deletes the returned instances one by one, so that the persistence provider can actually invoke @PreRemove callbacks on those entities.

实际上,一个衍生的删除查询是查询执行的一个快捷方式,然后基于结果调用CrudRepository.delete(Iterable<User> users)并与CrudRepositorydelete(…)方法的实现同步保持行为。

In fact, a derived delete query is a shortcut for executing the query and then calling CrudRepository.delete(Iterable<User> users) on the result and keeping behavior in sync with the implementations of other delete(…) methods in CrudRepository.

翻译部分版权归YahaCode团队所有。仅供学习研究之用,任何组织或个人不得私自以此用于任何形式的商业目的

发表评论