如何使用Akka使用Hibernate对数据库执行操作而不阻止Web客户端?
UPDATE:
原来这个错误是由dao.get()方法引起的 . 我更改了start()方法以获取实际对象而不是数据库中的id,现在我没有得到任何错误,但是没有发生任何事情(它像我之前所说的那样卡在em.merge()上) .
public CompletionStage<Result> start(SomeObject object) {
ExecutionContext ec = Akka.system().dispatchers().lookup("akka.actor.db-context");
return CompletableFuture.supplyAsync(() -> doStuff(object), play.libs.concurrent.HttpExecution.fromThread(ec))
.thenApply(i -> ok("Got result: " + i));
}
OUTDATED:
如果我尝试类似的东西:
@Transactional
public CompletionStage<Result> start(Long id) {
ExecutionContext ec = Akka.system().dispatchers().lookup("akka.actor.db-context");
return CompletableFuture.supplyAsync(() -> doStuff(dao.get(id)), play.libs.concurrent.HttpExecution.fromThread(ec))
.thenApply(i -> ok("Got result: " + i));
}
doStuff只执行entityManager.merge(),我得到:
[CompletionException:org.hibernate.SessionException:Session已关闭!]
要么
[CompletionException:java.lang.IllegalStateException:EntityManager已关闭]
当我使用下面的代码开始上面的过程时:
@Transactional
public Result mainMethod() {
List<SomeObject> allObjects= dao.getAll();
int size = allObjects.size();
for(int i = 0; i < size; i++) {
start(allObjects.get(i).getId());
}
return ok("Started");
}
然后,新创建的线程(actor)在尝试数据库操作时进入无限循环 .
谢谢!
完整堆栈跟踪:
play.api.http.HttpErrorHandlerExceptions $$匿名$ 1:执行异常在[[CompletionException:org.hibernate.SessionException::会话被关闭]!]在play.api.http.HttpErrorHandlerExceptions $ .throwableToUsefulException(280 HttpErrorHandler.scala) play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:206)at play.api.GlobalSettings $ class.onError(GlobalSettings.scala:160)at play.api.DefaultGlobal $ .onError(GlobalSettings.scala:188)at at play.api.http.GlobalSettingsHttpErrorHandler.onServerError(HttpErrorHandler.scala:98):在play.core在play.core.server.netty.PlayRequestHandler $$ anonfun $ $$ 2 $ anonfun申请$ 1.applyOrElse(100 PlayRequestHandler.scala) . server.netty.PlayRequestHandler $$ anonfun $ 2 $$ anonfun $ apply $ 1.applyOrElse(PlayRequestHandler.scala:99)at scala.concurrent.Future $$ anonfun $ recoverwith $ 1.apply(Future.scala:344)at scala.concurrent . 在play.api的scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)的未来$$ anonfun $ recover以$ 1.apply(Future.scala:343) . libs.iteratee.Execution $ trampoline $ .executeScheduled(Execution.scala:109)at play.api.libs.iteratee.Execution $ trampoline $ .execute(Execution.scala:71)at scala.concurrent.impl.CallbackRunnable.executeWithValue( Promise.scala:40)scala.concurrent.impl.Promise的scala.concurrent.impl.Promise $ DefaultPromise.tryComplete(Promise.scala:248)scala.concurrent.Promise $ class.complete(Promise.scala:55)at scala.concurrent.impl.Promise $ DefaultPromise.complete(Promise.scala:153)at scala.concurrent.java8.FuturesConvertersImpl $ P.accept(FutureConvertersImpl.scala:94)at scala.concurrent.java8.FuturesConvertersImpl $ P.accept(FutureConvertersImpl.scala:89)at at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:760)在java.util.concurrent.CompletableFuture $ UniWhenComplete.tryFire(CompletableFuture.java:736)在java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java: 474)at java.util.concurrent.CompletableFuture $ AsyncSupply.run(CompletableFuture.java:1595)at play.core.j.HttpExecutionCon在akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:39)在akka.dispatch.ForkJoinExecutorConfigurator $ AkkaForkJoinTask.exec(AbstractDispatcher.scala:405)在scala.concurrent:文本$$匿名$ 2.run(56 HttpExecutionContext.scala) .forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)在scala.concurrent.forkjoin.ForkJoinPool $ WorkQueue.runTask(ForkJoinPool.java:1339)在scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)在scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)引起:java.util.concurrent.CompletionException:org.hibernate.SessionException:会话关闭! at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273)at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280)at java.util.concurrent.CompletableFuture $ AsyncSupply.run(CompletableFuture.java) :1592)...省略了7个常见帧引起:org.hibernate.SessionException:会话关闭!在org.hibernate.internal.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:133)在org.hibernate.internal.SessionImpl.setCacheMode(SessionImpl.java:1455)在org.hibernate.jpa.spi.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java :1144)atg.hibernate.jpa.spi.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:1068)at daos.dao.get(dao.java:45)at controllers.DemoController.lambda $ start $ 0(DemoController.java:195 )在java.util.concurrent.CompletableFuture $ AsyncSupply.run(CompletableFuture.java:1590)...省略了7个常用帧
LE:
试过:
ExecutionContext ec = Akka.system().dispatchers().lookup("akka.actor.db-context");
return CompletableFuture.supplyAsync(() -> jpa.withTransaction("default", true, ()-> doStuff(dao.get(id))), play.libs.concurrent.HttpExecution.fromThread(ec))
.thenApply(i -> ok("Got result: " + i));
我得到了同样的错误 .
2 回答
@Transactional注释位于同步方法上 . 我想你需要在异步块内部进行交易 . 您可以使用jpa方法withTransaction而不是注释 . 它的签名(来自Play java api)
它应该是这样的:
注意,对withTransaction的调用中的第二个参数是对于readOnly操作(在你的案件) .
我用@asch的建议解决了这个问题:
控制器:
并在doStuff方法类中: