Search code examples
javahibernatejpaspring-transactions

JPA immediately fetching just after save causes NoResultException: No entity found for query


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?


Solution

  • 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.