2016-10-06 35 views
0

首先,抱歉,如果我問的是明顯的問題,或者問題本質上是愚蠢的。JPA只創建查詢一次

更多的學術問題需要知道我是否可以創建一個跨越或獨立於EntityManager的JPA查詢(命名或其他)。基本上,準備一次運行總是。我明白,我們只能從enitity管理器對象的createXXXQuery方法中獲得一個Query實例,但是,還有其他方法嗎?

這就是我要做的,

public class MyRepo { 
@PersistenceContext 
private EntityManager em; 

private Query aQueryIntentedtoBePreparedOnlyOnce; 

@PostConstruct 
public void prepareMyQuery(){ 
    aQueryIntentedtoBePreparedOnlyOnce = em.createQuery("...."); // Query with positional params 
    } 

    public void executeMyQuery(){ 
    aQueryIntentedtoBePreparedOnlyOnce.getResultList(); 
    } 
} 

這完全執行的第一次。但是,它第二次顯示「Entity Manager已關閉」。我明白這是因爲EM是Transaction的範圍。

這個EM是容器管理的(JTA - Spring),所以我不能在事務中擴展它。而且,使用會話bean不是一個選項。那麼,有沒有辦法只創建一次這個查詢?

PS:在哪裏命名查詢和查詢緩存來了?與命名查詢我似乎仍然每次都做createNamedQuery。什麼是查詢緩存計劃有沒有好的文檔呢?

另一個問題,爲什麼查詢只在EM或連接(JDBC)上創建?爲了準備查詢,我不需要知道我正在與哪個數據庫交談?如果沒有適當的連接,人們永遠無法執行一個?

+1

你不能。使用普通的hibernate,你可以使用'DetachedCriteria',但最終仍然需要成爲一個Criteria實例來執行,因此你仍然需要一個Session(或者JPA稱爲EntityManager)。但是,你爲什麼要這樣做?你不會獲得任何/很多的性能(它只會使用更多的內存),並且實際的查詢(如果已配置)由JDBC驅動程序緩存。 –

+0

@M。 Deinum我不必這樣做,只是想知道我是否錯過了一些東西。爲什麼它會消耗更多的內存?導致查詢是我的回購對象的成員? SQL不會隨參數改變什麼用途是JDBC驅動器緩存的SQL? – anchreg

+0

不可以。因爲'PreparedStatement'不是被綁定參數的查詢緩存的。你在內存中有更多的對象,因此更多的內存。現在你有一個非常短暫的對象,它很快就從內存中移除了。 –

回答

2

每個Query對象都綁定到特定的EntityManager並且不能在另一箇中重用,就像每個EntityManager綁定到一個JDBC連接一樣。

命名查詢是一種緩存編譯查詢和有用的元數據的方法。通常當你使用em.createQuery時,它每次都會解析它。它可能會在緩存中保留一些關於它的信息,因爲它很可能再次遇到相同的查詢,但這不是必需的。

查詢是通過調用createStatement(返回Statement),prepareStatement(返回一個PreparedStatement它繼承前一個)或prepareCall JDBC連接上(返回CallableStatement繼承了前兩個)創建的。那些Statement對象沒有切換到另一個連接的接口。根據驅動程序的不同,它們可能會被緩存在Java應用程序或服務器中。一條語句可以在同一連接上多次重複使用,但不會在其他連接上重複使用。

+0

好的。謝謝。所以,我不能阻止編譯JPQL,但是,可以通過使用命名查詢獲得性能? – anchreg

+0

半 - 是的。命名查詢會稍微提高性能,但不會太大。 JPA提供者可能會將它們存儲起來進行編譯。你只需要按名稱創建它們。通常通過註釋。 – coladict