使用 spring 数据 jpa 存储库在 Hql 查询之后进行 flush()

flush() after Hql querie using spring data jpa repository

我正在 spring 数据 jpa 存储库中使用 @Query 注释编写一些 hql 查询。我知道我可以使用存储库接口中的方法,但出于学习目的,我正在明确编写它们。

这是我的主要内容class

@SpringBootApplication
public class Main implements CommandLineRunner {

    @Autowired
    PersonRepository personRepository;

    public static void main( String[] args ) {
        SpringApplication.run(Main.class, args);
    }

    /**
     * if we delete the transactional annotation-> we get an exception
     */
    @Override
    @Transactional
    public void run( String... args ) throws Exception {
        saveOperation();
        deleteOperationUsingHql();
    }

    private void saveOperation() {
        Person p = new Person("jean", LocalDate.of(1977,12,12));
        personRepository.save(p);
    }

    private void deleteOperationUsingHql() {
        personRepository.deleteUsingHql(1L);
        personRepository.flush();
        Optional<Person> p = personRepository.findById(1L);
        if (p.isPresent()){
            System.out.println("still present");
        }
    }
}

我的 personRepository 接口

public interface PersonRepository  extends JpaRepository<Person, Long> {

      @Query(value = "select p from Person p where p.id=?1")
      List<Person> getById( Long id);

      @Modifying
      @Query(value = "delete from Person p where p.id=:id")
      void deleteUsingHql( Long id );
}

这个人class

@Entity
@Table(name = "Person")
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private LocalDate date;

   // constructors,getters...omitted for brievety
}

一切都运行很好,但是对于deleteOperationUsingHql(),即使我从数据库中删除了这个人,即使我将修改刷新到数据库,这个人id=1 ] 仍然由 findById(1L) 方法返回。我应该怎么做才能使 findById(1L) 返回一个空的 Optional.

我的第二个问题是关于@Transactional注释,我知道它的详细工作原理,但我不知道为什么如果我们删除它,我们会得到以下异常

Caused by: javax.persistence.TransactionRequiredException: Executing an update/delete query

有人可以解释为什么我在 @Transactional 被删除时会收到此异常。

even If I deleted the person from the database and even if I flush the modification to the database, the person with id=1 is still returned by the findById(1L) method

这很正常,因为您使用查询来删除人员,而不是实际使用存储库(以及 EntityManager)删除方法。查询完全绕过会话缓存,因此 Hibernate 不知道这个人已被删除,returns 实例在其缓存中。解决方案:不要使用查询。替代解决方案,删除后清除缓存(例如通过将 Modifying 注释的 clearAutomatically 标志设置为 true)。

Could someone explains why I'm getting this exception when @Transactional is removed.

因为删除@Transactional时,在执行该方法之前没有SPring启动事务,从报错信息可以看出,删除查询必须在事务内部执行.