I loop over person entities of a jpa streamresult and call for every single person an update service bean to update the name of the person entity. I understand, that envers is executed at the end of the transaction. Ok this works fine and all entities are updated and have an AUD table entry, but with a single revision for all.

How I tell spring to do a for every person entity a single transaction , so that envers writes for every updated entity a single update revision instead for all updated person entities? I tried also to put @Transactional(propagation = Propagation.REQUIRES_NEW) to the top of the update service class, but envers isn't triggered for every item. It seems that all updates are executed in one transaction, but I need a single transacion for every call of the update service bean.

The stream service:

@Service
class StreamService {

    @Autowired
    PersonRepository repo;

    @Autowired
    FooService fooService;

    @Transactional
    public void uppercaseAllNames() {
        Stream<Person> stream = repo.findAllPersons();
    
         // change name for each person
        stream.forEach(fooService::doFoo);
    }

}

The simplified update service:

@Service
@Transactional(propagation = Propagation.REQUIRES_NEW) // <=== create new transaction
class FooService {

    @Autowired
    PersonRepository repo;

    doFoo(Person person) {
        String name = person.getName();
        person.setName(name.toUpperCase());
        repo.save(person); // <=== save trigger envers
    }
}

Solution: The save operation trigger envers to create a revision per person entity, but this solution works in our project only with @Transactional(propagation = Propagation.REQUIRES_NEW). A single @Transactional doesn't work. The annotation can be placed at method or class level, booth places work.

2

There are 2 answers

0
Jens Schauder On BEST ANSWER

Remove the @Transactional from uppercaseAllNames. This will give you a separate transactions for the read and each write.

You'll need to add a personRepo.save(person) to the FooService.doFoo in order to persist the changes.

It might be that the second change is sufficient with Propagation.REQUIRES_NEW, but I find nested transactions rather confusing and would recommend to avoid them.

0
ProfDrM On

Had the same Problem and the Accepted Answer above worked. But I had to add readOnly=true to the outer Transaction.