I have a spring boot application running with hibernate. In my scheme I have City which can have multiple Resident(s). I have the following method to update the residents of a city:
public void updateResidentsInCity(long cityId) {
CompletableFuture
.supplyAsync(() -> residentsRepository.findAllByCityId(cityId))
.thenApply(residents -> {
// update fields of the resident objects
updateResidents(residents);
return residents;
})
.thenAccept(residents -> residentsRepository.saveAll(residents));
}
But this cause really bad performance issues, because the update running on a different thread, so the hibernate session is expired and when i call residentsRepository.saveAll(residents)
hibernate needs to fetch all the entities again.
I thought about two approaches to fix this issue and i'm wondering what is best (or maybe there are another approaches, of course):
- Just give up the multiple CompletableFuture(s)- putting all the operations under one
@Transactional
and make blocking calls:
@Transactional
public void updateResidentsInCity(long cityId) {
final List<Resident> residents = residentsRepository.findAllByCityId(cityId);
updateResidents(residents);
residentsRepository.saveAll(residents);
}
Now I can just call updateResidentsInCity()
in a different thread:
CompletableFuture.runAsync(() -> updateResidentsInCity(123))
In addition, allow hibernate to make batch update by adding those properties:
spring.jpa.properties.hibernate.jdbc.batch_size=50
spring.jpa.properties.hibernate.order_updates=true
- keep the same code with CompletableFuture(s), but make
residentsRepository.findAllByCityId()
areadOnly
transaction, and implement my own single native query for batch update:
public void updateResidentsInCity(long cityId) {
CompletableFuture
.supplyAsync(() -> residentsRepository.findAllByCityId(cityId)) // readOnly transaction
.thenApply(residents -> {
updateResidents(residents);
return residents;
})
.thenAccept(residents -> residentsRepository.batchUpdate(residents)); // new transaction, one native query
}
I will be glad to get some insights about which approach is better, and maybe another approaches I didn't think of. Please note that my application potentially should update many cities in the same time.