我们正在使用带有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)。
最佳,
答案 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
直接交互 - 以确保播放器已保存并发送消息。