为什么我们必须在Data Jpa中对查询使用@Modifying注释

Art*_*nko 39 java spring spring-annotations spring-data-jpa

例如,我的CRUD界面中有一个方法可以从数据库中删除用户:

public interface CrudUserRepository extends JpaRepository<User, Integer> {

    @Transactional
    @Modifying
    @Query("DELETE FROM User u WHERE u.id=:id")
    int delete(@Param("id") int id, @Param("userId") int userId);
}
Run Code Online (Sandbox Code Playgroud)

此方法仅适用于注释@Modifying.但是这里的注释需要什么?为什么不能分析查询并理解它是一个修改查询?

小智 36

这将触发向该方法注释的查询作为更新查询而不是选择查询.由于EntityManager在执行修改查询后可能包含过时的实体,因此我们会自动将其清除(有关详细信息,请参阅EntityManager.clear()的JavaDoc).这将有效地删除EntityManager中仍未处理的所有未刷新的更改.如果您不希望自动清除EntityManager,可以将@Modifying批注的clearAutomatically属性设置为false;

有关详细信息,您可以点击此链接: -

http://docs.spring.io/spring-data/jpa/docs/1.3.4.RELEASE/reference/html/jpa.repositories.html

  • @justMe那么你是说在最近的版本中,如果我们单独包含修改注释而没有任何像flush或clear这样的属性,那么这个注释是无用的并且什么也不做? (2认同)
  • @theprogrammer我所说的是那些默认情况下设置为 false 的标志,文档在这里https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/Modifying。 html,如果不设置它们会发生什么?请参阅下面尤纳斯的回答。或官方文档https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.modifying-queries (2认同)

Kus*_*ake 9

需要@Modifying注释的查询包括 INSERT、UPDATE、DELETE 和 DDL 语句。

添加@Modifying注释表示该查询不是针对 SELECT 查询的。


You*_*ans 6

警告!

使用@Modifying(clearAutomatically=true)将在持久性上下文中的托管实体上删除所有未决的更新,spring指出以下内容:

这样做会触发注释该方法的查询作为更新查询,而不是选择查询。由于EntityManager在执行修改查询后可能包含过时的实体,因此我们不会自动清除它(有关详细信息,请参阅EntityManager.clear()的JavaDoc),因为这会有效地将所有尚未刷新的更改丢弃在EntityManager中。如果希望自动清除EntityManager,则可以将@Modifying批注的clearAutomatically属性设置为true。

幸运的是,从Spring Boot 2.0.4.RELEASESpring Data 开始添加flushAutomatically标记(https://jira.spring.io/browse/DATAJPA-806),以执行修改后的查询检查参考https://docs.spring 之前自动刷新持久性上下文中的所有托管实体。 io / spring-data / jpa / docs / 2.0.4.RELEASE / api / org / springframework / data / jpa / repository / Modifying.html#flushAutomatically

因此,最安全的使用方式@Modifying是:

@Modifying(clearAutomatically=true, flushAutomatically=true)
Run Code Online (Sandbox Code Playgroud)

如果我们不使用这两个标志怎么办?

考虑以下代码:

repo {
   @Modifying
   @Query("delete User u where u.active=0")
   public void deleteInActiveUsers();

}
Run Code Online (Sandbox Code Playgroud)

方案1为什么 flushAutomatically

 service {
        User johnUser = userRepo.findById(1); // store in first level cache
        johnUser.setActive(false);
        repo.save(johnUser);

        repo.deleteInActiveUsers();// BAM it won't delete JOHN

        // JOHN still exist since john with active being false was not 
        // flushed into the database when @Modifying kicks in
    }
Run Code Online (Sandbox Code Playgroud)

方案2为什么clearAutomatically 在下面考虑johnUser.active已经为false

service {
       User johnUser = userRepo.findById(1); // store in first level cache
       repo.deleteInActiveUsers(); // john is deleted now 
       System.out.println(userRepo.findById(1).isPresent()) // TRUE!!!
       System.out.println(userRepo.count()) // 1 !!!

       // JOHN still exist since in this transaction persistence context
       // John's object was not cleared upon @Modifying query execution, 
       // John's object will still be fetched from 1st level cache 
       // `clearAutomatically` takes care of doing the 
       // clear part on the objects being modified for current 
       // transaction persistence context
}
Run Code Online (Sandbox Code Playgroud)

因此,如果-在同一个事务中-您在进行修改的对象之前或之后正在玩修改过的对象@Modifying,则使用clearAutomatically&(flushAutomatically如果没有)则可以跳过使用这些标志