【发布时间】:2016-12-14 08:45:24
【问题描述】:
如何使用 Akka 通过 Hibernate 对数据库执行操作而不阻塞 Web 客户端?
更新:
原来错误是由 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));
}
过时:
如果我尝试类似:
@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: 会话是 关闭!]
或
[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");
}
然后新创建的线程(actors)在尝试数据库操作时进入无限循环。
谢谢!
完整的堆栈跟踪:
play.api.http.HttpErrorHandlerExceptions$$anon$1:执行 异常[[CompletionException:org.hibernate.SessionException: 会话已关闭!]] 在 play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:280) 在 play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:206) 在 play.api.GlobalSettings$class.onError(GlobalSettings.scala:160) 在 play.api.DefaultGlobal$.onError(GlobalSettings.scala:188) 在 play.api.http.GlobalSettingsHttpErrorHandler.onServerError(HttpErrorHandler.scala:98) 在 play.core.server.netty.PlayRequestHandler$$anonfun$2$$anonfun$apply$1.applyOrElse(PlayRequestHandler.scala:100) 在 play.core.server.netty.PlayRequestHandler$$anonfun$2$$anonfun$apply$1.applyOrElse(PlayRequestHandler.scala:99) 在 scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:344) 在 scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:343) 在 scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32) 在 play.api.libs.iteratee.Execution$trampoline$.executeScheduled(Execution.scala:109) 在 play.api.libs.iteratee.Execution$trampoline$.execute(Execution.scala:71) 在 scala.concurrent.impl.CallbackRunnable.executeWithValue(Promise.scala:40) 在 scala.concurrent.impl.Promise$DefaultPromise.tryComplete(Promise.scala:248) 在 scala.concurrent.Promise$class.complete(Promise.scala:55) 在 scala.concurrent.impl.Promise$DefaultPromise.complete(Promise.scala:153) 在 scala.concurrent.java8.FuturesConvertersImpl$P.accept(FutureConvertersImpl.scala:94) 在 scala.concurrent.java8.FuturesConvertersImpl$P.accept(FutureConvertersImpl.scala:89) 在 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) 在 java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1595) 在 play.core.j.HttpExecutionContext$$anon$2.run(HttpExecutionContext.scala:56) 在 akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:39) 在 akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:405) 在 scala.concurrent.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:会话已关闭!在 java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273) 在 java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280) 在 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) 在 org.hibernate.jpa.spi.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:1068) 在 daos.dao.get(dao.java:45) 在 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));
我得到了同样的错误。
【问题讨论】:
-
也许我做错了,所以我更简单的问题是:如何使用 Play 的 Akka Actors 使非 Web 客户端阻止数据库操作?例如,启动一些更新操作,将某些字段设置为某些值,而无需让发送控制器操作的客户端等待结果(因为它与用户无关)。
标签: java hibernate playframework playframework-2.5