3

I've been implementing some business logic/validation with the Spring Data Rest and JPA repositories using repository validators as described in:

http://docs.spring.io/spring-data/rest/docs/current/reference/html/#events.

After digging deeper into the SDR code I noticed that the validators (or more generally, repository listeners) are not invoked within a transaction.

From the source code of org.springframework.data.rest.webmvc.RepositoryEntityController:

private ResponseEntity<ResourceSupport> createAndReturn(Object domainObject, RepositoryInvoker invoker,
            PersistentEntityResourceAssembler assembler, boolean returnBody) {
        // validation logic is implemented in the listener, no transaction yet
        publisher.publishEvent(new BeforeCreateEvent(domainObject));
        // invoker calls repository, which is wrapped in the transactional proxy, 
        // only then transaction begins
        Object savedObject = invoker.invokeSave(domainObject);
        publisher.publishEvent(new AfterCreateEvent(savedObject));

        PersistentEntityResource resource = returnBody ? assembler.toFullResource(savedObject) : null;

        HttpHeaders headers = prepareHeaders(resource);
        addLocationHeader(headers, assembler, savedObject);

        return ControllerUtils.toResponseEntity(HttpStatus.CREATED, headers, resource);
}

As seen in the code, the listeners are not called within a transaction, which could lead to eventual data consistency issues.

Am I missing something? Or the framework simply sets the transactional boundary incorrectly?

David Siro
  • 1,826
  • 14
  • 33
  • I think it is designed this way. 'Before' event should be sent before save and should be successful regardless of success of save. This a generic approach of spring, SDR only follows it. In my opinion inability to attach additional logic to repository operations makes whole concept hardly usable. So we have to use custom controllers in 80% of cases. – alexei-grigoriev Feb 24 '16 at 15:13
  • Well, I'm not quite positive about 'before' events being independent of the the actual save invocation. In the SDR [documentation](http://docs.spring.io/spring-data/rest/docs/2.4.4.RELEASE/reference/html/#validation), it is suggested to use validators as events listeners, thus actual repository call is dependent on the validation success. Anyway, I understand that underlying Spring Data implementation might not necessarily be JPA, but stating a simple note about about transactions in the docs would be indeed nice:) – David Siro Feb 28 '16 at 18:49
  • If your event listeners need to take part in a larger transaction, then you most likely don't need event listeners, but a full-fledged service. The documentation clearly states that Spring Data REST simply exposes repositories. – a better oliver Feb 29 '16 at 13:38

1 Answers1

3

In spring data rest the repository method would run its own transaction. I also think that this is problematic in some cases. At least the event handler should be run in the same transaction as the repository method.

There was a similar question here: Handle spring-data-rest application events within the transaction

Especially this answer provides a workaround that allows you to wrap the whole RepositoryEntityController method in a transaction - I think this is what you need most of the time:

https://stackoverflow.com/a/30713264/5371736

Community
  • 1
  • 1
Mathias Dpunkt
  • 11,594
  • 4
  • 45
  • 70
  • Thanks for the tips! In the end, our logic is quite simple, so we decided to have validators non-transactional, as simple optimistic locking is enough. However, in single problematic use case, where locking and updates of multiple entities are involved, we decided to go for a custom controller calling good old transactional service. – David Siro Feb 28 '16 at 18:57
  • _"At least the event handler should be run in the same transaction as the repository method"_ Why? – a better oliver Feb 29 '16 at 13:32
  • 4
    I think it is a common requirement to do some additional db access in your events - e.g. do some auditing. And you will easily come to a point where you want your update to be rolled back when the auditing fails. We often d messaging using spring-amqp after updates or creates - and if sending the messages fails we also want to roll back the transaction and vice versa. – Mathias Dpunkt Feb 29 '16 at 15:22