【问题标题】:Java Play 2.3 F.Promise No Entity Manager bound to this threadJava Play 2.3 F.Promise 没有实体管理器绑定到这个线程
【发布时间】:2015-05-05 13:19:00
【问题描述】:

我正在尝试同时访问 mysql 数据库以使用 F.Promise 获取对象列表,但我得到:

没有实体管理器绑定到这个线程

虽然在方法内部我调用了存储过程,但我用 JPA.withTransactionAsync 包装了它,但仍然得到相同的错误。

 import play.libs.F.*;
 import play.mvc.*;
 import java.util.concurrent.Callable;

 import static play.libs.F.Promise.promise;

 public class Application extends Controller {
 public static Promise<Result> index() {
    return promise(new Function0<Integer>() {
        public Integer apply() {
            return getUserId();
        }
    }).map(new Function<Integer,Result>() {
        public Result apply(Integer i) {
        return ok("Got " + i);
        }
    });

在 getUserId() 内部

public static int getUserId()
{
    return JPA.withTransactionAsync(.........);
}

【问题讨论】:

    标签: java mysql concurrency playframework


    【解决方案1】:

    这是一个已知问题 - 您可以查看有关它的讨论 here

    引用詹姆斯·罗珀的话...


    跨线程使用事务会引入死锁。问题来了:

    • 请求 A 获取连接
    • 请求 A 执行一些异步操作,并产生其线程
    • 请求 B 获取线程,尝试获取连接,但由于连接池为空而阻塞
    • 请求A的异步操作完成,进入队列执行,最终将连接返回池中,但由于线程被请求B持有,等待连接,无法执行,它永远不会得到它,因为它正在等待 A 归还它,它不能......

    所以我们陷入了僵局。上面的场景描述了一个简单的场景,只有一个连接和一个线程,但是我们有很多用户在更现实的场景中看到生产死锁,在连接池上阻塞了许多线程,并且许多连接持有线程被阻塞等待连接池阻塞线程让出。

    解决方案是使用异步连接池,不幸的是,JPA 不支持。一种解决方法是拥有一个用于异步获取连接的专用线程池,这样,当连接池耗尽时,专用线程将阻塞,但这不会影响任何事情(除了可能的嵌套尝试获取连接)因为它只用于从池中获取连接。


    所以,你有 3 个选择:

    1. 您可以使用this library 正确处理实体管理器的关闭,但仍然存在上述死锁问题。

    2. 使用JPA.withTransaction 而不是JPA.withTransactionAsync

    3. 使用 Ebean,没有这些问题。

    编辑:为了完整起见,我将添加选项 4(我的首选解决方案),即不使用 ORM 框架并将其替换为 jOOQ。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-12
      • 1970-01-01
      • 2012-02-03
      • 2023-03-05
      • 2011-12-11
      • 1970-01-01
      相关资源
      最近更新 更多