Skip to content

flush() doesn't work by default in @Transaction #3894

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
chikacow opened this issue May 17, 2025 · 2 comments
Closed

flush() doesn't work by default in @Transaction #3894

chikacow opened this issue May 17, 2025 · 2 comments
Labels
status: invalid An issue that we don't feel is valid

Comments

@chikacow
Copy link

chikacow commented May 17, 2025

Hi, I noticed a problem that when I am not manually using entityManager.flush() below, the result i got for tableNo in return statement and what I have in the database(which got the data updated) is different. For example, my input for tableNo is "a b c" and my expected result both for in database and the return is "abc". However I only have "abc" in the database and still "a b c" in the return statement. When I uncomment the entityManager.flush() things work perfectly, but do I have to do so since the flush() should be automatically done?

Seat.java

  @PreUpdate
    private void preUpdate() {
        this.tableNo = this.tableNo.trim().replaceAll("\\s+", "");;
    } 

SeatService.java

  @Transactional
      public Seat.SeatResponseDTO updateSeat(Long id, Seat.SeatRequestDTO requestDTO) {
          Seat seat = getSeatById(id); //which called
  
          if (!seat.getTableNo().equals(requestDTO.getTableNo())) {
              if (seatRepository.existsByTableNo(requestDTO.getTableNo())) {
                  throw new IllegalArgumentException("Table number already exists");
              }
              seat.setTableNo(requestDTO.getTableNo());
          }
  
          seat.setDescription(requestDTO.getDescription());
          seat.setStatus(TableStatus.fromString(requestDTO.getStatus()));
  
          /**
           * bug, this should be automatically called but i have to do it manually to achieve something obvious
           */
          entityManager.flush();
          
          return Seat.SeatResponseDTO.builder()
                  .tableNo(seat.getTableNo())
                  .description(seat.getDescription())
                  .status(seat.getStatus())
                  .build();
      }
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label May 17, 2025
@schauder
Copy link
Contributor

This is not a bug but normal JPA behavior. And completely unrelated to Spring Data JPA.

The life cycle event happens when data gets flushed to the database.
This happens at the end of the transaction or when you explicitly call flush.

In the first case you construct your DTO before the event handling happens, since you see the unmodified data.

@schauder schauder closed this as not planned Won't fix, can't repro, duplicate, stale May 19, 2025
@schauder schauder added status: invalid An issue that we don't feel is valid and removed status: waiting-for-triage An issue we've not yet triaged labels May 19, 2025
@chikacow
Copy link
Author

Thanks for your response!

I have resolved this. The problem is caused by the difference between @PrePersist and @PreUpdate.

When I call entityManager.persist(), the @PrePersist seems to work immediately while the @PreUpdate will only work until the flush() is activated.

That's why the result in my response DTO is different between my 2 methods updateSeat() and createSeat() (Which drove me crazy because the 2 functions basically does the same thing)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: invalid An issue that we don't feel is valid
Projects
None yet
Development

No branches or pull requests

3 participants