如何使用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:Session is 封闭!]
或
[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 $$ anon $ 1:执行 exception [[CompletionException:org.hibernate.SessionException: 会议结束!]] play.api.http.HttpErrorHandlerExceptions $ .throwableToUsefulException(HttpErrorHandler.scala:280) 在 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 play.api.http.GlobalSettingsHttpErrorHandler.onServerError(HttpErrorHandler.scala:98) 在 play.core.server.netty.PlayRequestHandler $$ anonfun $ 2 $$ anonfun $ $申请1.applyOrElse(PlayRequestHandler.scala:100) 在 play.core.server.netty.PlayRequestHandler $$ anonfun $ 2 $$ anonfun $ $申请1.applyOrElse(PlayRequestHandler.scala:99) 在 scala.concurrent.Future $$ anonfun $ recoverWith $ 1.适用(Future.scala:344) 在 scala.concurrent.Future $$ anonfun $ recoverWith $ 1.适用(Future.scala:343) 在scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)at at play.api.libs.iteratee.Execution $蹦床$ .executeScheduled(Execution.scala:109) 在 play.api.libs.iteratee.Execution $蹦床$ .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)at 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 $$匿名$ 2.run(HttpExecutionContext.scala:56) at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:39)at 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) at daos.dao.get(dao.java:45)at controllers.DemoController.lambda $启动$ 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));
我得到同样的错误。
答案 0 :(得分:0)
我使用@asch建议解决了这个问题:
控制器:
@Inject
private JPAApi jpa;
[...]
return CompletableFuture.supplyAsync(() -> jpa.withTransaction("default", false, ()-> doStuff(objectDAO.get(id))), play.libs.concurrent.HttpExecution.fromThread(ec))
.thenApply(i -> ok("Got result: " + i));
在doStuff方法类中:
private static final JPAApi jpaApi = Play.current().injector().instanceOf(JPAApi.class);
[...]
jpaApi.withTransaction(() -> {
EntityManager em = jpaApi.em();
em.merge(object);
});
[...]
答案 1 :(得分:-1)
@Transactional 注释位于同步方法上。我想你需要在异步块内部进行交易。您可以使用jpa方法 withTransaction 而不是注释。 它的签名(来自Play java api)
/**
* Run a block of code in a JPA transaction.
*
* @param name The persistence unit name
* @param readOnly Is the transaction read-only?
* @param block Block of code to execute
* @param <T> type of result
* @return code execution result
*/
public <T> T withTransaction(String name, boolean readOnly, Supplier<T> block);
它应该是这样的:
在控制器中注入JPAApi:
@Inject
JPAApi jpa;
通过调用jpa实现异步执行程序:
jpa.withTransaction("default", true, ()->doStuff(dao.get(id)), play.libs.concurrent.HttpExecution.fromThread(ec))
.thenApply(i -> ok("Got result: " + i)));
请注意,对 withTransaction 的调用中的第二个参数 true 适用于readOnly操作(在您的情况下)。