playframework 1.2.x:等待/异步和 JPA 事务

Posted

技术标签:

【中文标题】playframework 1.2.x:等待/异步和 JPA 事务【英文标题】:playframework 1.2.x: await / async and JPA transactions 【发布时间】:2016-09-13 14:19:24 【问题描述】:

我的 PUT 请求太长而无法运行。我想让它异步,使用延续(等待/承诺功能)。 我创建了一个修改我的实体的工作 (LongJobThatUpdatesThePassedEntity)

public static void myLongPut(@required Long id, String someData) 
       MyJpaModel myJpaModel = MyJpaModel.findById(id);

       //straightforward modifications
       updateMyJpaModel(someData);
       myJpaModel.save(); 

       //long processing modifications to entity, involving WS calls
       Promise<String> delayedResult = new LongJobThatUpdatesThePassedEntity(id).now();

       await(delayedResult);

       render(myJpaModel.refresh());

     

如何管理数据库事务?

在工作调用之前是否有提交?

作业有自己的数据库事务?

如果在回滚的LongJobThatUpdatesThePassedEntity 中存在问题,在updateMyJpaModel 中所做的修改是否会保留?

我可以在最后做render(myJpaModel.refresh()) 吗? 它会包含直截了当的修改和冗长的修改吗?

谢谢

【问题讨论】:

【参考方案1】:

我可以回答您关于 Play 1.4.3 的大部分问题,这是我目前使用的版本。我预计自 Play 1.2 以来没有太大变化。

数据库事务是如何管理的?

玩!使用“调用”处理作业和控制器操作的事务,这是一个特定于 Play 的概念。简而言之,对于任何调用,每个插件都有机会在被调用的方法运行之前和之后进行一些设置和清理。对于数据库访问,JPAPlugin.withinFilter 方法使用 JPA 类的辅助方法启动和关闭事务。

在工作调用之前是否有提交?

当您调用await(Future&lt;T&gt;) 时,它具有关闭当前事务并开始新事务的效果。具体机制是它抛出一个“暂停”异常,该异常会冒泡到PlayHandler$NettyInvocation 并导致afterInvocation 回调被调用。这会导致JPAPlugin.afterInvocation 调用 JPA.closeTx() 提交或回滚事务,视情况而定。

当 Job 退出并继续 await() 继续时。这也作为调用处理,因此事务以与以前相同的方式启动,使用JPAPlugin.withinFilter()。但是,与之前不同的是,控制器动作不是调用的目标,而是ActionInvoker.invoke() 调用invokeWithContinuation,它恢复保存的继续状态并通过从await() 返回来恢复执行。

JPA.withTransaction 看起来有一些特殊的逻辑可以在继续挂起/恢复期间保留相同的实体管理器。我认为没有这个,你将无法调用 refresh()。

在您的代码中,我认为在 await() 关闭事务和 Job 开始其事务之间存在竞争条件。也就是说,Job 的事务可能在控制器提交“等待之前”事务之前开始。为避免这种情况,您可以在调用Job.now() 之前显式调用JPA.closeTx()

根据代码检查,它看起来像 Play!实现时,Job 将退出并且 Job 的事务将在“after await()”事务打开之前关闭。不知道有没有 说明这是 await() 合同的预期部分的文档,因此如果这对您的应用程序至关重要,您可以通过在 Job.doJobWithResult() 方法返回之前提交事务来避免使用未记录的行为。

作业有自己的数据库事务?

是的,除非它被注释为没有交易。

如果 LongJobThatUpdatesThePassedEntity 出现回滚问题,updateMyJpaModel 中所做的修改是否会保留?

根据上面的解释,三个事务中的每一个都是独立的。如果一个被回滚,我看不出它会如何影响其他人。

【讨论】:

完成了,我终于避免使用 .refresh() 并在等待之后调用 Model.findById() 。

以上是关于playframework 1.2.x:等待/异步和 JPA 事务的主要内容,如果未能解决你的问题,请参考以下文章

playframework 1.2.x 如何在开发模式下每次播放重新加载时调用我的方法?

http chunked, tcp flow control 和 playframework 结合

在play framework 1.2.x, class JPABase分析中,为啥要调用saveAndCascade()?

Playframework 中 HTTPS 协议中的重定向控制器方法

Play Framework 1.2.4 在异步线程中同步作业:可能吗?

如何让 Playframework 在不发出请求的情况下开始在开发模式下运行应用程序?