同步 Hibernate 持久性 + Spring AMQP 发布事务

Synchronizing Hibernate persistence + Spring AMQP publish transactions

在我的应用程序中,用户创建了一个 post,它持久保存在数据库中 + 发布到 Spring amqp 队列

当用户创建一个 post 流点击控制器时

@RequestMapping(value="/createPost", method=RequestMethod.POST, consumes = "application/json", 
            produces = "application/json")
    public @ResponseBody Post createUserPost(@RequestBody(required=false) Post post, Principal principal){
        this.userService.persistPost(post);
        logger.info("post persistance successful");
        publishService.publishUserPosts(post);
        return post;
    }

有两个服务 persistPostpublishUserPosts 在控制器中调用的不同服务 classes 中。

发布服务

@Transactional
    public void publishUserPosts(Post post){
        try{
            logger.info("Sending user post to the subscribers");
            amqpTemplate.convertAndSend(post);
            }catch(AmqpException e){
                throw new MyAppException(e);
            }
    }

问题是两个服务调用 运行 在不同的事务下。如果 PublishPost 事务失败,post 仍然保留在数据库中。

为了将这两项服务置于单个事务下,我更改了代码并在 PublishPost class.

中注入了 persistPost 服务
@Transactional
    public void publishUserPosts(Post post){
        try{
            userService.persistPost(post);
            logger.info("post persistance successful");
            logger.info("Sending user post to the subscribers");
            amqpTemplate.convertAndSend(post);
            }catch(AmqpException e){
                throw new MyAppException(e);
            }
    }

我的问题

这是在单个事务下实现多项服务的最佳方法,还是我可以使用其他方法做得更好?

我认为您对交易的运作方式感到困惑。 HiberanteTransactionManager 只能处理数据库操作。要使其他部分也具有事务性,例如消息传递,您必须使用称为 Java 事务性 API (JTA) 的技术,它允许 合并 不同技术的事务到一笔大的 分布式 交易。在 Spring 中,这是由 JTATransactionManage 提供的。

尽管如此,在这种情况下(如果您遵循领域驱动设计模式)更可接受的设计是拥有一个 Application Service which acts as a facade to your domain and is responsible for keeping the transactional boundary. This Application Service then calls the Post Repository(您所谓的 userService)并最终发布信息。所以在伪代码中

class PostApplicationService {
   @Transactional
   public void publishUserPosts(Post post){
      postRepository.save(post);
      publishService.notifyNewPost(post);
   }
}

我会使用本地事件总线(例如 Spring 或 Guava 提供的事件总线)进行通知。但这只是我的偏好:).