Spring Data JpaRepository saveAndFlush within @Transactional not working

Viewed 9859

Currently I am facing a problem with Spring-Data/Hibernate that I will introduce briefly.

I am working on some simple Reporting functionality, that fetches Entities from a single table as Stream. This is working fine, but has to happen within a longer running Transaction, because the Connection to the Database needs to stay open. Within this transaction I want to constantly update a ReportEntity, which tracks the status and the progress of the process. Code looks basically like this:

    @Async
    @Transactional(isolation = Isolation.READ_UNCOMMITTED)
    public void process(Long reportId, SearchCriteria searchCriteriaTo) {

        ReportEntity report = reportRepository.findById(reportId).get();
        report.setStatus(ReportGenerationStatus.START);
        reportRepository.saveAndFlush(report);

        Stream<RawDataEntity> rawDataEntityStream = this.rawDataRepository
            .findAllFiltered(...);

        report.setStatus(ReportGenerationStatus.GENERATING_REPORT);
        report.setProgress(50);
        reportRepository.saveAndFlush(report);

        ...

        rawDataEntityStream.forEach(() -> DoSomething())

        ...

        report.setStatus(ReportGenerationStatus.FINISHED);
        report.setProgress(100);
    }

My problem is, that from my understanding saveAndFlush should write the intermediate steps of The ReportEntity into the database, but it does not. I am using a Posgres DB and verified this with PGAdmin and also I wrote a polling client that constantly fetches the ReportEntity.

    @Transactional(readOnly = true)
    public ReportEto getReportByKey(UUID key) {
        // entityManager.clear();
        ReportEntity reportEntity = this.reportRepository.findByKey(key);
        return getBeanMapper().map(reportEntity, ReportEto.class);
    }

But the status "GENERATING_REPORT" does not get written to the DB. Only after the final commit the status is updated to FINSIH. I tried to set the isolation level to "READ_UNCOMMITTED", but this also does not have an effect. The Hibernate Debug Logs however suggest, that a Update is triggered:

o.h.e.i.DefaultMergeEventListener        : EntityCopyObserver strategy: disallow
o.h.e.i.AbstractFlushingEventListener    : Processing flush-time cascades
o.h.e.i.AbstractFlushingEventListener    : Dirty checking collections
o.h.e.i.AbstractFlushingEventListener    : Flushed: 0 insertions, 1 updates, 0 deletions to 1 objects
o.h.e.i.AbstractFlushingEventListener    : Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
o.hibernate.internal.util.EntityPrinter  : Listing entities:
o.hibernate.internal.util.EntityPrinter  : com.capgemini.cusmesonlinereporting.reportmanagement.dataaccess.api.ReportEntity{downloadLink=null, externalUserId=MMUSTER, modificationCounter=0, creationTimestamp=2020-03-26T07:21:03.421700Z, name=2018-1-1_2020-3-23, progress=0, id=1000019, key=ecb0955f-b838-4f30-ac1f-dc94763ac810, status=GENERATING_REPORT}
org.hibernate.SQL                        : update Report set modificationCounter=?, creationTimestamp=?, downloadLink=?, externalUserId=?, key=?, name=?, progress=?, status=? where id=? and modificationCounter=?
Hibernate: update Report set modificationCounter=?, creationTimestamp=?, downloadLink=?, externalUserId=?, key=?, name=?, progress=?, status=? where id=? and modificationCounter=?

I could go ahead and make all the updates to the ReportEntity in a nested Transaction with a "REQUIRE_NEW" Transaction, but I dont want to run into potential DeadLocks because of the long running Transaction that might get executed multiple times in parallel. So my questions are:

  1. Why does saveAndFlush not work in this case ?
  2. are there any workarounds that do not involve creating nested transactions?
0 Answers
Related