JMS和JPA - 事务性服务的最佳实践

时间:2014-01-23 11:49:06

标签: java spring jms jta transactional

我们正在使用带有jpa和jms的spring框架。

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

以下是一个例子:

@Override
@Transactional
public void createAccount(PlayerDTO playerDTO) {

    Player newPlayer  = new Player(playerDTO);

    playerRepository.save(newPlayer);

    produceJmsMessage(new PlayerCreatedEvent());
 }

问题是,jms不是我们的交易过程的一部分。 (只有jpaTransactionManager) 因此,无论何时执行最后一行,都会触发消息,而不会对DB进行提交。

现在假设其中一个消息消费者试图获取播放器以处理某些内容但是!当他从数据库中取出玩家时,它还没有被提交!

在各种情况下,我们一直都会遇到这种情况。

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

所以问题是:

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

最佳,

2 个答案:

答案 0 :(得分:3)

sessionTransacted属性解决了我的问题,它实际上等到事务被提交后再触发事件。 (默认设置为OFF):

<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>

答案 1 :(得分:1)

您可以使用外观包装您的交易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直接交互 - 以确保播放器已保存并发送消息。