谨慎!
使用将删除持久性上下文中托管实体上的任何挂起的更新 spring 状态如下:@Modifying(clearAutomatically=true)
这样做会触发对方法进行批注的查询,将其作为更新查询而不是选择查询。由于在执行修改查询后,EntityManager 可能包含过时的实体,因此我们不会自动清除它(有关详细信息,请参阅 EntityManager.clear() 的 JavaDoc),因为这会有效地删除 EntityManager 中仍挂起的所有未刷新的更改。如果希望自动清除 EntityManager,则可以将@Modifying注释的 clearAutomatic 属性设置为 true。
幸运的是,从 Spring Data 添加标志 (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#flushAutomaticallySpring Boot 2.0.4.RELEASE
flushAutomatically
所以最安全的使用方法是:@Modifying
@Modifying(clearAutomatically=true, flushAutomatically=true)
如果我们不使用这两个标志会发生什么??
请考虑以下代码:
repo {
@Modifying
@Query("delete User u where u.active=0")
public void deleteInActiveUsers();
}
方案 1 为什么自动刷新
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
}
场景 2 为什么清除自动
在下面考虑 johnUser.active 已经是 false
service {
User johnUser = userRepo.findById(1); // store in first level cache
repo.deleteInActiveUsers(); // you think that 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
}
因此,如果 - 在同一事务中 - 您正在玩修改后的对象,那么使用&如果不是,那么您可以使用这些标志跳过@Modifying
clearAutomatically
flushAutomatically
顺便说一句,这是您应该始终在服务层上放置注释的另一个原因,以便您只能为同一事务中的所有托管实体提供一个持久性上下文。由于持久性上下文仅限于休眠会话,因此您需要知道一个会话可以包含几个事务,请参阅此答案以获取更多信息 https://stackoverflow.com/a/5409180/1460591 Spring数据的工作方式是它将事务一起(也称为事务隔离)联接到一个事务中(默认隔离(必需))请参阅此答案以获取更多信息 https://stackoverflow.com/a/25710391/1460591@Transactional
如果您有多个事务(例如,在服务上没有事务注释),则可以将事物连接在一起,因此您将按照spring数据的工作方式进行多个会话,因此您有多个持久性上下文,这意味着即使使用相同的已删除/修改元素,您也可以删除/修改持久性上下文中的元素,可能会在另一个事务的持久性上下文中获取和缓存,这将导致由于错误而导致的业务错误决策或未同步的数据flushAutomatically