xmen-5
xmen-5

Reputation: 1906

flush() after Hql querie using spring data jpa repository

I'm writing some hql queries using the @Query annotation in a spring data jpa repository. I know that I can use the methods from the repository interface, but for learning purpose, I'm writing them explicitly.

Here is my Main 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");
        }
    }
}

My personRepository interface

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 );
}

The person 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
}

everything is running well, but for the deleteOperationUsingHql(), 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. What should I do for making the findById(1L) returning an empty Optional.

My second question is about the @Transactional annotation, I know how it works in details, but I don't know why if we delete it, We get the following exception

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

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

Upvotes: 1

Views: 2622

Answers (1)

JB Nizet
JB Nizet

Reputation: 691933

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

That's normal, because you use a query to delete the person, instead of actually using the repository (and thus the EntityManager) delete method. Queries bypass the session cache completely, so Hibernate has no idea that this person has been deleted, and returns the instance in its cache. Solution: don't use a query. Alternate solution, clear the cache after deleting (for example by setting the clearAutomaticallyflag of the Modifying annotation to true).

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

Because when @Transactional is removed, there is no transaction being started by SPring before executing the method, and as you can see from the error message, delete queries must be executed inside a transaction.

Upvotes: 3

Related Questions