Search code examples
javaspringtransactionstransactional

Spring @Transactional how to "stop" transaction


I have a controller that calls a method on a service class which should do the following:

  1. update database (using DAO 1)
  2. update database (using DAO 2)
  3. sendEmail (using email service)

(1) and (2) should be atomic and if both succeed the email should be sent. If I annotate the service method with @Transactional the email is sent even if the DB updates fail (and this is not desired). Furthermore if the email fails the DB update is rolled back (which is not desired either).

My understanding is that moving 3. to a separate method on the same service class would not help. Annotating the sendEmail method with @Transactional and a different propagation behavior (e.g. NEVER or REQUIRES_NEW) does not seem to help either.

Is it possible to achieve the behavior with proper annotations?


Solution

  • You need to have a transaction for the two first steps, then have the transaction committed, and finally send the email. The easiest way to do that is to introduce an additional bean

    Controller:

    beanA.process();
    

    Bean A:

    // not transactional
    public void process() {
        beanB.updateDatabase();
        sendEmail();
    }
    
    private void sendEmail() {
        ...
    }
    

    Bean B:

    @Transactional
    public void updateDatabase() {
        dao1.update();
        dao2.update();
    }