playframework 1.2.x:等待/异步和 JPA 事务
playframework 1.2.x: await / async and JPA transactions
我有一个太长的 PUT 请求 运行。我想让它异步,使用延续(await/promise 特性)。
我创建了一个作业 (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())
吗?
它会包含直接修改和长修改吗?
谢谢
我可以回答你关于 Play 1.4.3 的大部分问题,这是我目前使用的版本。我预计自 Play 1.2 以来不会发生太大变化。
How are the DB transactions managed?
玩吧!使用 "invocation" 处理作业和控制器操作的事务,这是一个特定于 Play 的概念。简而言之,对于任何调用,每个插件都有机会在调用的方法运行之前和之后进行一些设置和清理。对于数据库访问,JPAPlugin.withinFilter
方法使用 JPA class 的辅助方法启动和关闭事务。
is there a commit before the job's call?
当您调用await(Future<T>)
时,它具有关闭当前交易并开始新交易的效果。具体机制是它抛出一个"Suspend"异常,它冒泡到PlayHandler$NettyInvocation
并导致调用afterInvocation
回调。这导致 JPAPlugin.afterInvocation
调用
JPA.closeTx()
根据需要提交或回滚事务。
当作业退出并恢复 await() 继续时。这也作为调用处理,因此事务以与以前相同的方式启动,使用 JPAPlugin.withinFilter()
。但是,与之前不同的是,控制器操作不是调用的目标,而是 ActionInvoker.invoke()
调用 invokeWithContinuation
,它恢复保存的继续状态并通过从 await()
返回恢复执行。
JPA.withTransaction
看起来它有一些特殊的逻辑来在延续 suspend/resume 中保留相同的实体管理器。我想如果没有这个,你将无法调用 refresh()。
在您的代码中,我认为在 await() 关闭事务和作业开始其事务之间存在竞争条件。也就是说,Job 的事务有可能在控制器提交 "before await" 事务之前开始。为避免这种情况,您可以在调用 Job.now()
.
之前显式调用 JPA.closeTx()
根据代码检查,看起来像这样玩!已实施,碰巧 Job 将退出并且 Job 的事务将在 "after await()" 事务打开之前关闭。我不知道有没有
说明这是 await() 合同的预期部分的文档,因此如果这对您的应用程序必不可少,您可以通过在 Job.doJobWithResult()
方法 returns 之前提交事务来避免使用未记录的行为。 =28=]
the job has it's own DB transaction?
是的,除非它被注释为没有交易。
if there is an issue in the LongJobThatUpdatesThePassedEntity that rollsback, the modifications done in updateMyJpaModel are persisted?
根据上面的解释,三笔交易都是独立的。如果一个被回滚,我看不出它会对其他人有什么影响。
我有一个太长的 PUT 请求 运行。我想让它异步,使用延续(await/promise 特性)。
我创建了一个作业 (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())
吗?
它会包含直接修改和长修改吗?
谢谢
我可以回答你关于 Play 1.4.3 的大部分问题,这是我目前使用的版本。我预计自 Play 1.2 以来不会发生太大变化。
How are the DB transactions managed?
玩吧!使用 "invocation" 处理作业和控制器操作的事务,这是一个特定于 Play 的概念。简而言之,对于任何调用,每个插件都有机会在调用的方法运行之前和之后进行一些设置和清理。对于数据库访问,JPAPlugin.withinFilter
方法使用 JPA class 的辅助方法启动和关闭事务。
is there a commit before the job's call?
当您调用await(Future<T>)
时,它具有关闭当前交易并开始新交易的效果。具体机制是它抛出一个"Suspend"异常,它冒泡到PlayHandler$NettyInvocation
并导致调用afterInvocation
回调。这导致 JPAPlugin.afterInvocation
调用
JPA.closeTx()
根据需要提交或回滚事务。
当作业退出并恢复 await() 继续时。这也作为调用处理,因此事务以与以前相同的方式启动,使用 JPAPlugin.withinFilter()
。但是,与之前不同的是,控制器操作不是调用的目标,而是 ActionInvoker.invoke()
调用 invokeWithContinuation
,它恢复保存的继续状态并通过从 await()
返回恢复执行。
JPA.withTransaction
看起来它有一些特殊的逻辑来在延续 suspend/resume 中保留相同的实体管理器。我想如果没有这个,你将无法调用 refresh()。
在您的代码中,我认为在 await() 关闭事务和作业开始其事务之间存在竞争条件。也就是说,Job 的事务有可能在控制器提交 "before await" 事务之前开始。为避免这种情况,您可以在调用 Job.now()
.
JPA.closeTx()
根据代码检查,看起来像这样玩!已实施,碰巧 Job 将退出并且 Job 的事务将在 "after await()" 事务打开之前关闭。我不知道有没有
说明这是 await() 合同的预期部分的文档,因此如果这对您的应用程序必不可少,您可以通过在 Job.doJobWithResult()
方法 returns 之前提交事务来避免使用未记录的行为。 =28=]
the job has it's own DB transaction?
是的,除非它被注释为没有交易。
if there is an issue in the LongJobThatUpdatesThePassedEntity that rollsback, the modifications done in updateMyJpaModel are persisted?
根据上面的解释,三笔交易都是独立的。如果一个被回滚,我看不出它会对其他人有什么影响。