如何在Java中同步并发Web服务调用
我目前正在用Java开发一些由SAP系统触发的web服务(带有MySQL连接的&JPA)。 为了简化我的问题,我将这两个关键实体称为如何在Java中同步并发Web服务调用,java,web-services,jpa,persistence,Java,Web Services,Jpa,Persistence,我目前正在用Java开发一些由SAP系统触发的web服务(带有MySQL连接的&JPA)。 为了简化我的问题,我将这两个关键实体称为bloggentry和Comment。一个博客条目可以有多个注释。一条评论总是只属于一条博客条目 所以我有三个服务(我不能也不想重新定义它们,因为它们是由我从SAP导出的WSDL定义的,并用于与其他系统并行通信):CreateBlogEntry,CreateComment,CreateCommentForUpcomingBlogEntry 它们被正确触发,单独调用时
bloggentry
和Comment
。一个博客条目
可以有多个注释
。一条评论
总是只属于一条博客条目
所以我有三个服务(我不能也不想重新定义它们,因为它们是由我从SAP导出的WSDL定义的,并用于与其他系统并行通信):CreateBlogEntry
,CreateComment
,CreateCommentForUpcomingBlogEntry
它们被正确触发,单独调用时,CreateBlogEntry
或CreateComment
绝对没有问题
但是:服务CreateCommentForUpcomingBlogEntry
发送注释和一个“外键”来识别“即将到来的”BlogEntry
。在内部,它还调用CreateBlogEntry
来创建实际的BlogEntry
这两个服务由于其异步性质而同时存在。
所以我有两个选择:
创建一个虚拟的博客条目
,并将注释
连接到它,并在创建博客条目
到达后更新博客条目
等待CreateBlogEntry
,然后将注释连接到新的BlogEntry
目前我正在尝试前一个,但一旦这两个服务都完全执行,我就会得到两个博客条目
。其中一个只有CreateCommentForUpcomingBlogEntry
提供的ID
,但它与注释
正确连接(反之亦然)。另一个bloggentry
包含所有其他信息(例如postDate
或body
),但是注释
没有连接到它
以下是服务实现的代码片段CreateCommentForUpcomingBlogEntry
:
@EJB
private BlogEntryFacade blogEntryFacade;
@EJB
private CommentFacade commentFacade;
...
List<BlogEntry> blogEntries = blogEntryFacade.findById(request.getComment().getBlogEntryId().getValue());
BlogEntry persistBlogEntry;
if (blogEntries.isEmpty()) {
persistBlogEntry = new BlogEntry();
persistBlogEntry.setId(request.getComment().getBlogEntryId().getValue());
blogEntryFacade.create(persistBlogEntry);
} else {
persistBlogEntry = blogEntries.get(0);
}
Comment persistComment = new Comment();
persistComment.setId(request.getComment().getID().getValue());
persistComment.setBody(request.getComment().getBody().getValue());
/*
set other properties
*/
persistComment.setBlogEntry(persistBlogEntry);
commentFacade.create(persistComment);
...
@EJB
private BlogEntryFacade blogEntryFacade;
...
List<BlogEntry> blogEntries = blogEntryFacade.findById(request.getBlogEntry().getId().getValue());
BlogEntry persistBlogEntry;
Boolean update = false;
if (blogEntries.isEmpty()) {
persistBlogEntry = new BlogEntry();
} else {
persistBlogEntry = blogEntries.get(0);
update = true;
}
persistBlogEntry.setId(request.getBlogEntry().getId().getValue());
persistBlogEntry.setBody(request.getBlogEntry().getBody().getValue());
/*
set other properties
*/
if (update) {
blogEntryFacade.edit(persistBlogEntry);
} else {
blogEntryFacade.create(persistBlogEntry);
}
...
这是一种无法让事情按预期发生的摆弄
遗憾的是,我还没有找到同步这些同步服务调用的方法。我可以让CreateCommentForUpcomingBlogEntry
休眠几秒钟,但我认为这不是正确的方式
我是否可以强制我的facades
的每个实例及其相应的EntityManager
重新加载其数据集?我是否可以将请求放入某种队列中,该队列将根据特定条件清空
那么:让它等待博客条目存在的最佳做法是什么呢?
提前感谢,,
大卫
信息:
- GlassFish服务器3.1.2
- EclipseLink,版本:EclipsePersistenceServices-2.3.2.v20111125-r10461
如果您确定收到一个CreateBlogEntry
呼叫,请将CreateCommentForUpcomingBlogEntry
呼叫排队,并在收到CreateBlogEntry
呼叫后对其进行处理
由于您在应用程序服务器上,对于队列,您可能可以使用自动刷新到存储的JMS队列,或者使用DB缓存引擎(Ehcache?),以防您收到大量调用或希望提供跨重启的恢复机制。如果日志条目具有相同id,为什么不签入CreateBlogEntry
(由CreateCommentForUpcomingBlogEntry
创建)已经存在?如果是,则更新而不是创建。这正是我当前正在尝试的操作(请参阅第二个代码段)。这是罪过。奇怪的是,您得到了两个条目(具有相同的唯一Id?)我可能不得不说,ID指的是发布SAP系统生成的值,实际上不是ID,数据库有自己的一组主键(真正唯一的ID)。现在,我已通过让CreateCommentForUpcomingBlogEntry
-线程休眠10秒,并通过调用getEntityManager().getEntityManager().getCache().ReceictAll()清除EntityManger的缓存,使代码正常运行我仍然不相信这是最好的解决方案:(换句话说,blogEntryFacade.edit(persistBlogEntry);
无法更新当前记录,但创建了一个新记录?听起来有点问题。你确定你的持久性策略可以吗?