JPA Eclipselink - 返回相同会话的多个EntityManagerFactory实例

时间:2017-04-06 22:42:27

标签: java jpa jdbc eclipselink

我理解EntityManagerFactory(EMF1)的实例有自己的EntityManager和session。如果我使用与EMF1相同的凭据创建另一个EntityManagerFactory(EMF2)实例,那么它应该有自己的连接池和所以会话。但它不是,因为这个原因,如果一切都相同,会话定制器也被调用一次

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

1 个答案:

答案 0 :(得分:0)

调试JPA代码后,我通过为每个实体管理器工厂提供唯一的会话名称解决了我的问题。

问题:

如果未提供 PersistenceUnitProperties.SESSION_NAME / eclipselink.session-name ,则 EntityManagerSetupImpl.getOrBuildSessionName 方法尝试使用两个工厂相同的连接属性创建会话名称。

首次使用会话名称作为 EntityManagerFactoryProvider 中的键创建并缓存 EntityManagerSetupImpl 对象。 对于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