在我的应用程序中,用户创建了一个帖子,该帖子被持久化在数据库中,并发布到Spring amqp队列
当用户创建post flow到达控制器时
@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;
}
有两个服务persistPost
&控制器中调用的不同服务类中的publishUserPosts
。
Publish Service
@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仍然在db中持久化。
为了将两个服务置于一个事务中,我更改了代码&在PublishPost
类中注入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提供的。
无论上述情况如何,在这种情况下(如果您遵循领域驱动的设计模式),更被接受的设计是使用一个应用程序服务,它充当您的领域的facade,并负责保持事务边界。这个应用程序服务然后调用Post Repository(您称之为userService
)并最终发布消息。在伪代码
class PostApplicationService {
@Transactional
public void publishUserPosts(Post post){
postRepository.save(post);
publishService.notifyNewPost(post);
}
}
我将使用本地事件总线(如Spring或Guava提供的总线)执行通知。但这只是我的偏好:)