Search code examples
javaspring-data-jpajpql

Spring Data JPA - JPQL update query - printing out unupdated value


Trying out doing update Queries in Spring Data JPA. In my test method (see below) I'm saving one student with firstName="Bill" and lastName="Smith". How can it be that I'm getting "Bill" printed out to the console (very last line), given that studentRespository.findByFirstName("John") actually gives a list with one member? Any help appreciated...

    @Modifying(flushAutomatically = true)
    @Transactional
    @Query("update Student s set s.firstName = ?1 where s.lastName= ?2")
    public void updateFirstNameByLastName(String firstName, String lastName)

    @Test
    public void updateStudentFirstNameByLastName() {
        studentRepository.save(student); //student.firstName="Bill", student.lastName="Smith"
        studentRepository.updateFirstNameByLastName("John", "Smith");
        List<Student> studentList = studentRepository.findByFirstName("John"); // size 1
        System.out.println(studentList.get(0).getFirstName()); // "Bill"
    }


Solution

  • According to the JPA’s entity lifecycle states save() method may not write your changes to database immediately.

    Since we use @Modifying in update query, this triggers the query annotated to the method as an updating query instead of a selecting one.

    Reason for above issue is, when we save(), the persistence context of this with outdated entities may still there after the execution of the modifying query. EntityManager do not automatically clear it. If you wish the EntityManager to be cleared/flushed automatically, you can set the @Modifying annotation’s clearAutomatically and flushAutomatically attribute to true. Check this official doc Modifying Queries.

    Annotation Type Modifying

    clearAutomatically(true/false) - Defines whether we should clear the underlying persistence context after executing the modifying query. (Default -false)

    flushAutomatically(true/false) - Defines whether we should flush the underlying persistence context before executing the modifying query. (Default -false)

    Add this @Modifying(clearAutomatically = true, flushAutomatically = true) to the updateFirstNameByLastName method as below.

    @Modifying(clearAutomatically = true, flushAutomatically = true)
    @Transactional
    @Query("update Student s set s.firstName = ?1 where s.lastName= ?2")
    public void updateFirstNameByLastName(String firstName, String lastName)