簡體   English   中英

Java Play 2.3 F.Promise沒有實體管理器綁定到此線程

[英]Java Play 2.3 F.Promise No Entity Manager bound to this thread

我正在嘗試同時訪問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(.........);
}

這是一個已知問題-您可以在此處查看其討論。

引用James Roper ...


跨線程使用事務會導致死鎖。 這是問題所在:

  • 請求A獲得連接
  • 請求A執行一些異步操作,並產生其線程
  • 請求B獲取線程,嘗試獲取連接,但由於連接池為空而阻塞
  • 請求A的異步操作完成,因此它進入隊列執行,並最終將連接返回到池中,但是由於線程由請求B保留,正在等待連接,因此它將無法執行。永遠不會得到,因為它正在等待A返回它,但它不能....

所以我們陷入了僵局。 上面的場景描述了一個只有一個連接和一個線程的簡單場景,但是在更現實的場景中,我們有很多用戶看到生產死鎖,在這種現實場景中,連接池上有許多線程被阻塞,許多連接保持線程被阻塞以等待連接池阻止線程產生。

解決方案是使用異步連接池,不幸的是,JPA不支持該池。 解決方法是有一個專用線程池,該線程池用於異步獲取連接,這樣,當連接池用盡時,專用線程將阻塞,但這不會影響任何事情(可能是嵌套的嘗試獲得連接)因為它僅用於從池中獲取連接。


因此,您有3個選擇:

  1. 您可以使用此庫來正確處理實體管理器的關閉,但仍會遇到上述死鎖問題。

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

  3. 使用沒有這些問題的Ebean。

編輯:為了完整起見,我將添加選項4(我的首選解決方案),該選項不使用ORM框架,而是將其替換為jOOQ。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM