我们使用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
进行交互 - 以确保保存播放器和发送消息。