简体   繁体   English

JMS和JPA-交易服务最佳做法

[英]JMS and JPA - transactional services best practices

We are using the spring framework with jpa and jms. 我们在jpa和jms中使用spring框架。

Most of our services involves DB persistence and JMS message throwing. 我们的大多数服务都涉及数据库持久性和JMS消息引发。

Here is an example: 这是一个例子:

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

    Player newPlayer  = new Player(playerDTO);

    playerRepository.save(newPlayer);

    produceJmsMessage(new PlayerCreatedEvent());
 }

Problem is, that jms is not part of our transactional process. 问题是,jms不是我们交易过程的一部分。 (only jpaTransactionManager) and therefore whenever the last line executed the message is fired without the commit against the DB taking place. (仅jpaTransactionManager),因此每执行完最后一行,就会触发该消息,而不会发生对数据库的提交。

Now imagine that one of the message consumers is trying to fetch the player in order to process some stuff but! 现在想象一下,消费者的消息之一是试图获取播放器以处理一些东西,但是! when he fetches the player from the db it is not been committed yet! 当他从数据库获取播放器时,尚未提交!

That happens to us all the time in a wide variety of scenarios. 在各种各样的情况下,我们一直都在发生这种情况。

Now, of-course we can use JTA but the performance impact is unbearable, and moreover its seems to be really unpopular in regards to documentations and stuff, 现在,我们当然可以使用JTA,但是对性能的影响是无法忍受的,而且就文档和内容而言,它似乎确实不受欢迎,

So the question is: 所以问题是:

How do developers mitigate this issue we described here? 开发人员如何缓解我们在此描述的问题? (without JPA). (没有JPA)。

Best, 最好,

sessionTransacted property solved my problem, it actually waits until transaction is committed before firing the events. sessionTransacted属性解决了我的问题,它实际上要等到事务提交后才触发事件。 (this is set to OFF by default): (默认情况下设置为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>

You could wrap your transactional PlayerService - or whatever it is that is responsible for saving the player - with a facade. 您可以使用立面包装事务性PlayerService或负责保存播放器的任何内容。 The PlayerService could just be responsible for saving the player transactionally - and the facade could be responsible for invoking the PlayerService and then generating the message. PlayerService可能只是负责以事务方式保存播放器-而Facade可能负责调用PlayerService然后生成消息。 Splitting out the send operation from the PlayerService would ensure that the Player is committed before the message is generated. PlayerService分离发送操作将确保在生成消息之前提交Player For example: 例如:

@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);
    }

    ...
}

And then that could be wrapped with some sort of facade. 然后可以用某种外观包裹起来。

@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());
    }
}

Client code would then interact with the PlayerFacade rather than the PlayerService directly - to ensure that both the player is saved and message sent. 这样,客户端代码将与互动PlayerFacade而非PlayerService直接-以确保双方的球员被保存和发送消息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM