2017-04-06 75 views
0

我瞭解一個EntityManagerFactory(EMF1)的實例有它自己的EntityManager和會話。如果我使用與EMF1相同的憑據創建EntityManagerFactory(EMF2)的另一個實例,那麼它應該有它自己的連接池和會話。但它不是因爲這個原因會話定製也被稱爲一次,如果一切是相同JPA Eclipselink - 多個EntityManagerFactory實例返回相同的會話

package test.jpa.factory; 

import java.sql.Connection; 
import java.util.HashMap; 
import java.util.Map; 

import javax.persistence.EntityManager; 
import javax.persistence.EntityManagerFactory; 
import javax.persistence.Persistence; 

import org.eclipse.persistence.config.PersistenceUnitProperties; 
import org.eclipse.persistence.config.SessionCustomizer; 
import org.eclipse.persistence.sessions.Session; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 

public class TestEntityManagerFactory { 
    private static Logger logger = LoggerFactory.getLogger(TestEntityManagerFactory.class); 
    public static final String JDBC_URL = "javax.persistence.jdbc.url"; 
    public static final String JDBC_USER = "javax.persistence.jdbc.user"; 
    public static final String JDBC_PASSWD = "javax.persistence.jdbc.password"; 
    public static final String WAREHOUSE_PERSISTENCE_UNIT = "etl-dw"; 

    public static void main(String[] args) throws Exception { 
     String host = "xxxxcccc"; 
     String port = "1521"; 
     String user = "skipvpd"; 
     String pwd = "abcd"; 
     String service = "test_svc1"; 
     System.out.println("Same user multiple EMF"); 
     printSession(host, port, user, pwd, service); 
     printSession(host, port, user, pwd, service); 

     System.out.println("Different user multiple EMF"); 
     user = "1032"; 
     pwd = "abcd"; 
     printSession(host, port, user, pwd, service); 
     user = "1033"; 
     printSession(host, port, user, pwd, service); 

    } 

    private static void printSession(String host, String port, String user, String pwd, String serviceName) 
      throws Exception { 
     EntityManagerFactory emf = getEntityManagerFactory(host, port, user, pwd, serviceName); 
     EntityManager em = emf.createEntityManager(); 
     em.getTransaction().begin(); 
     Session session = (Session) em.unwrap(org.eclipse.persistence.sessions.Session.class); 
     Connection connection = (Connection) em.unwrap(java.sql.Connection.class); 
     System.out.println("con_hashcode=" + connection.hashCode() + ",session_hashcode=" + session.hashCode() 
       + ",em_hashcode=" + em.hashCode() + ",emf_hashcode=" + emf.hashCode()); 
     em.getTransaction().commit(); 
     em.close(); 

    } 

    private static EntityManagerFactory getEntityManagerFactory(String host, String port, String user, String pwd, 
      String serviceName) { 

     Map<String, String> jpaConfig = new HashMap<String, String>(); 
     try { 
      String jdbcURL = "jdbc:oracle:thin:@" + host + ":" + port + "/" + serviceName; 

      jpaConfig.put("javax.persistence.jdbc.url", jdbcURL); 
      jpaConfig.put(JDBC_USER, user); 
      jpaConfig.put(JDBC_PASSWD, pwd); 

      jpaConfig.put(PersistenceUnitProperties.SESSION_CUSTOMIZER, 
        TestEntityManagerFactory.ETLSessionCustomizer.class.getName()); 

     } catch (Throwable t) { 
      logger.error("ERROR=\"Error occured in getJPAConfiguration\" EXCEPTION={}", t); 
     } 
     return Persistence.createEntityManagerFactory(WAREHOUSE_PERSISTENCE_UNIT, jpaConfig); 

    } 

    public static class ETLSessionCustomizer implements SessionCustomizer { 

     public void customize(Session session) { 
      System.out.println("customize is called for session_hash_code=" + session.hashCode()); 
     } 
    } 
} 

同一用戶的多個EMF

定製的要求session_hash_code = 1193471756

con_hashcode = 675100200 ,session_hashcode = 1193471756,em_hashcode = 627727856,emf_hashcode = 179294202

con_hashcode = 675100200,session_hashcode = 1193471756,em_hashcode = 166919726,emf_hashcode = 1305777754

不同用戶的多個EMF

定製被調用session_hash_code = 1240796303 con_hashcode = 738369543,session_hashcode = 1240796303,em_hashcode = 1017841629,emf_hashcode = 1760715967

定製被調用session_hash_code = 1161255903

con_hashcode = 92699135,session_hashcode = 1161255903,em_hashcode = 1535875885,emf_hashcode = 2054926467

+0

默認情況下,會議將在同一線程被重用。如果您不想重複使用同一個會話,則必須明確向工廠詢問。 –

+0

感謝您的回覆@GuillaumeF。我認爲這不是真的,如果是這樣,那麼它是一個更大的問題。您能否指出我對這個假設的文檔或源代碼。 在我的測試代碼中,如果用戶不同,會話不會共享。問題在兩個不同的實體經理工廠之間。 –

+0

結果是邏輯,它非常簡單。使用同一個用戶獲得2個會話,您必須關閉連接(會話),或者始終直到會話結束/結束時纔會獲得相同的會話。 2個用戶有2個會話。 – bilelovitch

回答

0

調試JPA代碼後,我通過爲每個實體管理器工廠提供唯一的會話名稱來解決我的問題。

問題:

如果PersistenceUnitProperties.SESSION_NAME/eclipselink.session名沒有提供那麼EntityManagerSetupImpl.getOrBuildSessionName方法嘗試使用連接屬性是相同的兩個工廠,以創建會話名稱。

第一次EntityManagerSetupImpl對象被創建並使用會話名作爲關鍵字裏面EntityManagerFactoryProvider緩存。 對於EntityManagerFactory的第二個實例(具有相同的會話名稱),它找到已在緩存中的實例,因此不會創建新實例,而是共享爲第一個EntityManagerFactory創建的現有實例。

在我的示例中,如果添加以下代碼,您將看到會話定製程序調用兩次的不同會話和哈希碼。

jpaConfig.put(PersistenceUnitProperties.SESSION_NAME, String.valueOf(System.nanoTime())); 

這裏是變更後的輸出

Same user multiple EMF 
customize is called for session_hash_code=1173577197 
con_hashcode=1091009906,session_hashcode=1173577197,em_hashcode=1569793443,emf_hashcode=1681793106 
customize is called for session_hash_code=649715211 
con_hashcode=1908828843,session_hashcode=649715211,em_hashcode=327304249,emf_hashcode=1296892976 
相關問題