仅当Spring交易成功完成交易时,才发送SendEmail

时间:2019-01-23 01:05:31

标签: java spring spring-data-jpa spring-transactions

在这种情况下,我想在数据库中创建用户并向用户发送带有AWS SES的电子邮件。

  1. 如果用户在数据库成功中提交事务=>发送电子邮件
  2. 如果发送电子邮件AWS SES失败(已检查的异常)=>在数据库中回滚用户创建
  3. 如果数据库中的用户提交事务失败=>不要使用AWS向用户发送电子邮件

我的代码存在问题:如果我的sendEmail方法抛出异常,则提交事务。

配置:带有spring-data-jpa的Spring-Boot项目

class EmailServiceImpl {   

    @Transactional(rollbackFor = Exception.class)
    @Override
    public User createUserAndSendEmail(UserDto userDto) throws UserEmailException {
        try {
            //rollback userCreation if sendEmail throw a checkedException
            User user = userService.create(userDto);
            sendEmail(user);
            return user;

        } catch (Exception exception) {
            throw new UserEmailException(exception.getMessage());
        }
    }

    //don't send email if userCommit in database failed
    private void sendEmail(User user) {
        amazonEmailService.sendMail(user);
    }
}

class UserServiceImpl {    

   @Transactional(propagation = Propagation.REQUIRES_NEW)
   @Override
   public User create(UserDto userDto) throws Exception {
       User user = mapp(userDto);
       return userRepository.save(user);
   }
}

1 个答案:

答案 0 :(得分:2)

要在TX提交后执行某些操作,可以将@TransactionalEventListenerTransactionPhase.AFTER_COMMIT一起使用(默认设置)。将您要执行的操作放入TransactionalEventListener中:

使用ApplicationEventPublisher发布UserCreatedEvent

public class EmailServiceImpl {   

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Transactional(rollbackFor = Exception.class)
    public User createUserAndSendEmail(UserDto userDto) throws UserEmailException {
        try {
            User user = userService.create(userDto);

            //Publish UserCreatedEvent such the UserCreatedEventHandler can handled it after TX commit
            applicationContext.publishEvent(new UserCreatedEvent(user));

            return user;
        } catch (Exception exception) {
            throw new UserEmailException(exception.getMessage());
        }
    }
}

TX提交后,UserCreatedEvent将由此处理程序处理:

@Component
public class UserCreatedEventHandler {

    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void handle(UserCreatedEvent event) {    
        try{
            amazonEmailService.sendMail(user);
            System.out.println("Good, can send email.");
        }catch(Exception exception){
            System.out.println("Sad, fail to send email , so remove user from DB...");
            userService.remove();
        }
    }
}

Deinum的出色表现。如果您使用我的建议,则必须将userService.create()更改为@Transactional(propagation = Propagation.REQUIRES)