'Why does the repository in an application event handler provide values that have not been updated?
I am working on a Spring Boot application with the JpaRepository.
There are actions in the application that are triggered by a scheduler.
After changing and saving an entity, an event is triggered to notify the rest of the system.
I now have the problem that the value was not updated when the event handler retrieves the entity from the repo.
Below is a highly simplified code section that hopefully clarifies the problem.
A scheduler triggers an action every given time:
@Component
public class MyScheduler {
//...
@Scheduled(cron = "0 * * * * *")
public void scheduleSomething() {
entityService.doSomething();
}
//...
A service modifies and stores an entity and then triggers an event to notify the system:
//...
@Transactional
@Override
public void doSomething() {
//...
var entityId = // some other code
var entity = entityRepo.findById(entityId);
entity.setName("new name");
eventMulticaster.multicastEvent(new MyEvent<>(this, entityRepo.save(entity)));
// If the entity is retrieved from the repo again, the name has been correctly changed!
//...
//...
When the event handler queries the entity, the value is not updated:
//...
@Transactional
@Override
public void onApplicationEvent(ApplicationEvent event) {
//...
var entityFormEvent = ((MyEntity) event.getPayload());
print(entityFromEvent.getName()); // Prints the updated value.
var entityFromRepo = entityRepo.findById(entityFromEvent);
print(entityFromRepo.getName()); // Prints the value before the change!
//...
It would be great if someone could help me and explain what I am doing wrong.
Thank you very much!
Solution 1:[1]
Spring Event Listeners are synchronous unless you explicitly use @Async annotation and make it asynchronous. This means when the below line is called the transaction of doSomething is not yet committed.
eventMulticaster.multicastEvent(new MyEvent<>(this, entityRepo.save(entity)));
Thus you will not see the changes in onApplicationEvent method when you retrieve from entityRepo.
You can try using JpaRepository.saveAndFlush which will save and flush the changes immediately to Database and it should work.
eventMulticaster.multicastEvent(new MyEvent<>(this, entityRepo.saveAndFlush(entity)));
UPDATE
The other thing you can try is removing the @Transactional annotation from your onApplicationEvent method which will force the transaction created from doSomething method to be used.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
