I can't save and then immediately retrieve saved entities in another service with JPA and Hibernate.
In microservice A I create a list of my entities, saving it via JpaRepository.saveAll()
without any errors, and then I do POST request on another microservice B, in which I fetch entities which were saved before, but fetching causes NoResultException: No entity found for query
I save my entities with JpaRepository.saveAll(dossiers)
method and then calling entityManager.flush()
, but it seems does not save immediately into database
the code is:
//Microservice A
@Transactional
public ResponseEntity<?> checkDocuments(List<UploadDossierModel> dossierModels, String token) {
// ...
dossiers = dossierRepository.saveAll(dossiers);
// ...
entityManager.flush();
startTask(tuple, "process"); // pass some info about dossiers (ids, aux info etc.)
}
and in startTask():
//Microservice A
@Transactional
public void startTask(Map<Integer, Object[]> tuple, String bpKey) {
Map<String, Object> variables = new HashMap<>();
ObjectMapper mapper = new ObjectMapper();
String s;
try {
s = mapper.writeValueAsString(tuple);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
variables.put("valuesJson", s);
entityManager.flush();
feignClient.startBp(bpKey, variables); // do POST request on microservice B with feign
}
and in Microservice B:
// Microservice B
// ...
for (String id : tuple.keySet()) {
Dossier dossier = entityManager.createQuery(
"select td from Dossier td join fetch td.temporaryDocumentMapper tdc where td.id = :id",
Dossier.class)
.setParameter("id", Integer.valueOf(id))
.getSingleResult(); // javax.persistence.NoResultException: No entity found for query
// ...
}
And even if I manually put some id that exist in database all works fine, the problem is exactly with newly saved data.
I already tried using saveAndFlush()
instead of saveAll()
but nothing changed.
My repository is extending JpaRepository<Dossier, Integer>.
I believe it is related with transactions, I think while second transaction in microservice B is trying to fetch newly saved entities first transaction in microservice A is still saving them, but I'm not sure, I tried every trick that I found and nothing changed.
How I can ensure that entites will save before calling a microservice B so microservice B can properly read newly saved entities?
One important thing to understand that the database transaction gets committed once the method annotated with @Transactional is completed (yes, outside the scope of your code). So basically, you're right, the B microservice tries to read the data that is not in the database yet. I believe that what you need to do is to invoke the B microservice in an asynchronous way (i.e. in a different thread taken from a pool or use an asynchronous CDI Observer) to allow the @Transactional method to complete before you try to read the freshly saved data elsewhere.