Управление событиями транзакций Spring решает проблему разделения асинхронных бизнес-операций @TransactionalEventListener и TransactionSynchronizationManager Transaction

Справочная информация. В бизнесе часто необходимо отправлять сообщения или события для асинхронного вызова других компонентов для выполнения соответствующих бизнес-операций после выполнения операций с базой данных (завершение отправки транзакции).
Например: после успешной регистрации пользователя отправляется код активации или электронное письмо с активацией. Если пользователь сохраняет данные, выполняется асинхронная операция для отправки кода активации или электронного письма с активацией. Однако после сохранения предыдущим пользователем происходит откат базы данных, и происходит откат базы данных. На самом деле пользователь не прошел успешную регистрацию, но получил код активации или электронное письмо с активацией. На этом этапе нам срочно требуется завершить транзакцию базы данных перед выполнением асинхронных операций.

@Autowired
private UserDao userDao;
@Autowired
private JmsProducer jmsProducer;

public User saveUser(User user) {
    
    
    // 保存用户
    userDao.save(user);

    // 发送激活码或激活邮件
    jmsProducer.sendEmail(user.getId());
}

// -------------------------------------
public void sendEmail(int userId) {
    
    
    /*
     * 获取待接收邮件的用户。(如果上面的保存用户方法还未提交事务,则实际数据还未插入到数据库中,此时会返回null)
    */
    User user = userDao.get(userId);
    // 可能抛NullPointException
    String email = user.getEmail();
    mailService.send(email);
}

Решение
1. После Spring 4.2 используйте аннотацию @TransactionalEventListener

/**
 * 业务Service
 */
@Service
@Transactional
public class FooService {
    
    
    @Autowired
    private  ApplicationEventPublisher applicationEventPublisher;

    public User saveUser(User user) {
    
    
        userDao.save(user);
        // 注册事件
        applicationEventPublisher.publishEvent(new SavedUserEvent(user.getId()));
    }
}

// -------------------------------------
/**
 * 保存用户事件
 */
public class SavedUserEvent {
    
    
    private int userId;
    
    public SavedUserEvent(int userId) {
    
    
        this.userId = userId;
    }
    
    // getter and setter
}

// ---------------------------------
/**
 * 事件侦听,处理对应事件
 */
@Component
public class FooEventListener() {
    
    
    @Autowired
    private UserDao userDao;
    @Autowired
    private MailService mailService;

    @TransactionalEventListener
    public sendEmail(SavedUserEvent savedUserEvent) {
    
    
        User user = userDao.get(userId);
        String email = user.getEmail();
        mailService.send(email);
    }
}

Использование TransactionSynchronizationManager и TransactionSynchronizationAdapter

@Autowired
private UserDao userDao;
@Autowired
private JmsProducer jmsProducer;

public User saveUser(User user) {
    
    
    // 保存用户
    userDao.save(user);
    final int userId = user.getId();

    // 事务提交后调用
    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
    
    
        @Override
        public void afterCommit() {
    
    
            jmsProducer.sendEmail(userId);
        }
    });
}

Примечание. Приведенный выше код будет выполнен после фиксации транзакции.Если он находится в нетранзакционном контексте, будет выдано исключение java.lang.IllegalStateException: синхронизация транзакции не активна.
Улучшенный код:

@Autowired
private UserDao userDao;
@Autowired
private JmsProducer jmsProducer;

public User saveUser(User user) {
    
    
    // 保存用户
    userDao.save(user);
    final int userId = user.getId();

    // 兼容无论是否有事务
    if(TransactionSynchronizationManager.isActualTransactionActive()) {
    
    
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
    
    
            @Override
            public void afterCommit() {
    
    
                jmsProducer.sendEmail(userId);
            }
        });
    } else {
    
    
        jmsProducer.sendEmail(userId);
    }
}

Supongo que te gusta

Origin blog.csdn.net/weixin_43832604/article/details/118303935
Recomendado
Clasificación