1

I'm working with Spring Boot 1.5.2.RELEASE and a PostgreSQL 9.5 database.

File entity:

@Entity
public class File implements Serializable {

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

    private String externalUid;
}

File repository looks like:

public interface FileRepository extends JpaRepository<File, Long> {

    @Modifying
    @Query("UPDATE File f SET f.externalUid =:externalUid WHERE f.id =:id")
    void setExternalLink(@Param("id") Long id, @Param("externalUid") String externalId);
}

After when I save new file (with flush) and execute update on it, then get this file from repository, then I have outdated entity. But when I have executed clear() [1] on entityManager before executing modifying query, then I get the updated entity:

String externalUid = UUID.randomUUID().toString();

File file = new File();
File savedFile = fileRepository.saveAndFlush(file);

// [1] entityManager.clear();

fileRepository.setExternalLink(savedFile.getId(), externalUid);

File updatedFile = fileRepository.findOne(savedFile.getId());

System.out.print(updatedFile.getExternalUid()); // null

This issue quite similar with this one: Spring Boot Data JPA - Modifying update query - Refresh persistence context. But in my case I execute saveAndFlush() instead of save().

In that regard can somebody explain me why we need to clear persistence context before executing modifying query and why repository returns me the outdated entity?

Zeromus
  • 4,472
  • 8
  • 32
  • 40
  • Because the entity will be retrieved from the first level cache instead of doing an actual query to the database. When clearing you remove the entity from the first level cache and a query is needed to retrieve it again. – M. Deinum Apr 10 '18 at 09:39

1 Answers1

1

The main point is that hibernate cache doesn't know anything about DML-style query you do.

So if you don't clear the cache and perform an update directly on the database, the cached object in question will be outdated.

Calling clear() will empty the cache and force hibernate to hit the database on subsequent queries.

Zeromus
  • 4,472
  • 8
  • 32
  • 40
  • Actually this code snipped executed in the spring test (with "rollback on" transaction), so in any case (with clear or without) no changes was performed on database... – George Zalizko Apr 10 '18 at 10:25
  • Yes there where changes due to your DML statement. Using SQL bypasses the object model, due to the cache (as explained twice) that isn't detect. Clearing the cache will result in a hit to the database and the hit to the database will lead to flushing of pending queries before doing the actual retrieval. The fact that a transaction already committed or not has nothing to do with this. – M. Deinum Apr 10 '18 at 11:21
  • Hmm.. okey. I have understood more or less. Then explain me please why after upgrading to the spring-boot 1.5.11(spring-data-jpa 1.11.11) and when I set `@Modifying(flushAutomatically=true)` then it works, without `clear()`? – George Zalizko Apr 11 '18 at 10:37