When using the @EventListener functionality with Spring Data's repositories the behavior is different than when calling the same code procedural.

My persistent objects publish events using the following base class:

  public abstract class Aggregate  {

      @Transient
      private transient final Set<Object> events = new LinkedHashSet<>();

      protected <T> T registerEvent(T event) {
          this.events.add(event);
          return event;
      }

      @DomainEvents
      Collection<Object> events() {
          return Collections.unmodifiableSet(events);
      }

      @AfterDomainEventPublication
      void clearEvents() {
          this.events.clear();
      }
  }

My event listening class is implemented as follows:

  class Service {

      @EventListener
      public void listener(SomeEvent event) {
          someOtherRepository.save(someOtherPersistentObject);
          someOtherCode();
      }
  }

When the listener is triggered and someOtherRepository's save(…) method fails a rollback will be issued. But someOtherCode() is executed regardless of the rollback.

But when I remove all @EventListening functionality and call the listener(…) method directly after the point where the originating repository is responsible for firing the event. Then I get a different behavior. Then someOtherCode() is never executed and the someOtherRepository.save(…) method fails immediately.

The original service responsible for publishing the event looks like this

public OriginatingService {
    @Transactional
    public void someMethod() {
        originatingRepoDifferentFromSomeOtherRepo.save(something);

Why is this happening and is there a way to force the same behavior onto my event listening implementation?

1 Answers

2
Alan Hay On Best Solutions

Because writes to the database may be delayed until transaction commit i.e. when the transactional method returns.

Update as below to explicitly trigger an immediate flush:

 @EventListener
  public void listener(SomeEvent event) {
      someOtherRepository.saveAndFlush(someOtherPersistentObject);
      someOtherCode();
  }