JMS和JPA-交易服务最佳实践



我们使用JPA和JMS的弹簧框架。

我们的大多数服务都涉及数据库持久性和JMS消息投掷。

这是一个示例:

@Override
@Transactional
public void createAccount(PlayerDTO playerDTO) {
    Player newPlayer  = new Player(playerDTO);
    playerRepository.save(newPlayer);
    produceJmsMessage(new PlayerCreatedEvent());
 }

问题是,JMS不是我们交易过程的一部分。(只有jpatransactionmanager)因此,每当执行最后一行时,就会发出消息,而无需针对DB的提交。

现在可以想象,消费者正在尝试获取玩家以处理一些东西,但是!当他从DB中获取播放器时,尚未投入!

一直在多种情况下发生在我们身上。

现在,我们可以使用JTA,但是性能的影响是难以忍受的,而且在文档和内容方面,它似乎确实不受欢迎,

所以问题是:

开发人员如何减轻我们在此处描述的问题?(没有JPA)。

最好,

session TransActed属性解决了我的问题,它实际上等到交易启动之前,直到启动事件。(默认情况下,这将关闭):

<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="cachingConnectionFactory" />
    <property name="messageConverter" ref="eventConverter" />
    <property name="sessionTransacted" value="true"/>
</bean>

您可以包装交易 PlayerService或任何负责拯救播放器的东西 - 带有立面。PlayerService可能只是负责通过交易保存播放器 - 外墙可能负责调用PlayerService然后生成消息。从PlayerService分开发送操作将确保在生成消息之前提交Player。例如:

@Service
public class PlayerServiceImpl implements PlayerService {
    @Autowired
    private PlayerRepository playerRespository;
    @Override
    @Transactional
    public void savePlayer(PlayerDTO playerDTO) {
        Player newPlayer  = new Player(playerDTO);
        // Responsible for saving the player only
        playerRepository.save(newPlayer);
    }
    ...
}

然后可以用某种外墙包裹。

@Service
public class PlayerFacade {
    @Autowired
    private PlayerService playerService;
    public void createAccount(PlayerDTO playerDTO) {
        playerService.savePlayer(playerDTO);
        // Generate the message after successful save.
        // The player would be committed at this point because
        // the savePlayer method (and thus transaction) has completed
        produceJmsMessage(new PlayerCreatedEvent());
    }
}

客户端代码然后将与PlayerFacade而不是直接与PlayerService进行交互 - 以确保保存播放器和发送消息。

最新更新