在纯JPA设置中获取数据库连接

Jac*_*cob 59 java orm hibernate jpa jdbc

我们有一个JPA应用程序(使用hibernate),我们需要调用一个需要JDBC数据库连接作为参数的旧报告工具.是否有一种简单的方法可以访问hibernate设置的JDBC连接?

小智 53

根据这里hibernate文档,

连接连接()

不推荐.(计划在4.x中删除).更换取决于需要; 做直接的JDBC东西使用doWork(org.hibernate.jdbc.Work)...

请改用Hibernate Work API:

Session session = entityManager.unwrap(Session.class);
session.doWork(new Work() {

    @Override
    public void execute(Connection connection) throws SQLException {
        // do whatever you need to do with the connection
    }
});
Run Code Online (Sandbox Code Playgroud)


Pas*_*ent 51

您想要获得该连接的位置尚不清楚.一种可能性是从底层的Hibernate得到它Session被使用EntityManager.使用JPA 1.0,您必须执行以下操作:

Session session = (Session)em.getDelegate();
Connection conn = session.connection();
Run Code Online (Sandbox Code Playgroud)

请注意,这getDelegate()是不可移植的,这个方法的结果是特定于实现的:上面的代码在JBoss中工作,对于GlassFish你必须适应它 - 看一下使用EntityManager.getDelegate()要小心.

在JPA 2.0中,事情要好一些,您可以执行以下操作:

Connection conn = em.unwrap(Session.class).connection();
Run Code Online (Sandbox Code Playgroud)

如果您在容器内运行,则还可以对已配置的内容执行查找DataSource.

  • 这在Hibernate 4中不起作用. (10认同)
  • 是的,在Hibernate 3.x中不推荐使用`connection()`,它们正在改变API(我不认为你会喜欢你的用例的新API).但是计划对Hibernate 4.x进行更改,这会给你一些时间. (6认同)
  • 使用EclipseLink似乎不可行.你无法从Session获得连接.看来你可以解开连接 - "Connection conn = em.unwrap(Connection.class)`.怀疑这是便携式的,不过...... (3认同)
  • 当我做其中任何一个时,我都会收到弃用警告.我可以忍受它,如果一个必须但它有点烦人(:它不像我想要做到这一点,它只是务实的最简单的方法来推动事情. (2认同)

小智 29

如果您使用的是JAVA EE 5.0,最好的方法是使用@Resource注释将数据源注入类的属性(例如EJB)以保存数据源资源(例如Oracle数据源)遗留报告工具,这种方式:

@Resource(mappedName="jdbc:/OracleDefaultDS") DataSource datasource;
Run Code Online (Sandbox Code Playgroud)

稍后您可以获取连接,并以这种方式将其传递给旧版报告工具:

Connection conn = dataSource.getConnection();
Run Code Online (Sandbox Code Playgroud)

  • +1我认为这是唯一正确的解决方案.其他人依赖于不可移植的,特定于产品的(Hibernate,EclipseLink)代码. (3认同)

小智 22

如果您使用EclipseLink:您应该在JPA事务中访问Connection

entityManager.getTransaction().begin();
java.sql.Connection connection = entityManager.unwrap(java.sql.Connection.class);
...
entityManager.getTransaction().commit();
Run Code Online (Sandbox Code Playgroud)


Lui*_*r15 14

由于@Paccal建议的代码被@Jacob所提及的弃用,我发现这另一种方式对我有用.

import org.hibernate.classic.Session;
import org.hibernate.connection.ConnectionProvider;
import org.hibernate.engine.SessionFactoryImplementor;

Session session = (Session) em.getDelegate();
SessionFactoryImplementor sfi = (SessionFactoryImplementor) session.getSessionFactory();
ConnectionProvider cp = sfi.getConnectionProvider();
Connection connection = cp.getConnection();
Run Code Online (Sandbox Code Playgroud)

  • `org.hibernate.engine.spi.SessionFactoryImplementor中不推荐使用`getConnectionProvider()` (3认同)
  • `getConnectionProvider()`在Hibernate 5中不再可用. (2认同)

Sas*_*ota 13

使用Hibernate 4/5:

Session session = entityManager.unwrap(Session.class);
session.doWork(connection -> doSomeStuffWith(connection));
Run Code Online (Sandbox Code Playgroud)


Jin*_*won 6

”一词与“ 休眠 ”一词不匹配。

我正在分享代码。

假设我们可以定义一种使用Connection从派生的方法EntityManager

static <R> applyConnection(final EntityManager manager,
                           final Function<Connection, R> function) {
    if (manager == null) {
        throw new NullPointerException("manager is null");
    }
    if (function == null) {
        throw new NullPointerException("function is null");
    }

    // we gonna fill here up

    throw new RuntimeException("failed to work with a connection");
}
Run Code Online (Sandbox Code Playgroud)

EclipseLink

如上面的链接所述,它有些简单。

  • 请注意,EntityManager必须将联接到,Transaction否则该unwrap方法将返回null。(根本不是一个好举动。)
  • 我不确定关闭连接的责任。
static <R> applyConnection(final EntityManager manager,
                           final Function<Connection, R> function) {
    if (manager == null) {
        throw new NullPointerException("manager is null");
    }
    if (function == null) {
        throw new NullPointerException("function is null");
    }

    // we gonna fill here up

    throw new RuntimeException("failed to work with a connection");
}
Run Code Online (Sandbox Code Playgroud)

冬眠

基本上,应该使用以下代码来完成。

// --------------------------------------------------------- EclipseLink
try {
    final Connection connection = manager.unwrap(Connection.class);
    if (connection != null) { // manage is not in any transaction
        return function.apply(connection);
    }
} catch (final PersistenceException pe) {
    logger.log(FINE, pe, () -> "failed to unwrap as a connection");
}
Run Code Online (Sandbox Code Playgroud)

好吧,我们(至少我是)可能不想要任何特定于供应商的依赖性。代理进入救援。

try {
    // See? You shouldn't fire me, ass hole!!!
    final Class<?> sessionClass
            = Class.forName("org.hibernate.Session");
    final Object session = manager.unwrap(sessionClass);
    final Class<?> returningWorkClass
            = Class.forName("org.hibernate.jdbc.ReturningWork");
    final Method executeMethod
            = returningWorkClass.getMethod("execute", Connection.class);
    final Object workProxy = Proxy.newProxyInstance(
            lookup().lookupClass().getClassLoader(),
            new Class[]{returningWorkClass},
            (proxy, method, args) -> {
                if (method.equals(executeMethod)) {
                    final Connection connection = (Connection) args[0];
                    return function.apply(connection);
                }
                return null;
            });
    final Method doReturningWorkMethod = sessionClass.getMethod(
            "doReturningWork", returningWorkClass);
    return (R) doReturningWorkMethod.invoke(session, workProxy);
} catch (final ReflectiveOperationException roe) {
    logger.log(Level.FINE, roe, () -> "failed to work with hibernate");
}
Run Code Online (Sandbox Code Playgroud)

OpenJPA

我不确定OpenJPA是否已提供一种使用方法,unwrap(Connection.class)但可以通过上述链接之一中描述的方法来完成。

目前尚不清楚关闭连接的责任。该文档(上述链接之一)似乎讲得很清楚,但我的英语不好。

try {
    final Class<?> k = Class.forName(
            "org.apache.openjpa.persistence.OpenJPAEntityManager");
    if (k.isInstance(manager)) {
        final Method m = k.getMethod("getConnection");
        try {
            try (Connection c = (Connection) m.invoke(manager)) {
                return function.apply(c);
            }
        } catch (final SQLException sqle) {
            logger.log(FINE, sqle, () -> "failed to work with openjpa");
        }
    }
} catch (final ReflectiveOperationException roe) {
    logger.log(Level.FINE, roe, () -> "failed to work with openjpa");
}
Run Code Online (Sandbox Code Playgroud)

附件

static <U, R> R applyConnection(
        final EntityManager manager,
        final BiFunction<Connection, U, R> function, final U u) {
    if (manager == null) {
        throw new NullPointerException("manager is null");
    }
    if (function == null) {
        throw new NullPointerException("function is null");
    }
    return applyConnection(manager, t -> function.apply(t, u));
}

static void acceptConnection(
        final EntityManager manager, final Consumer<Connection> consumer) {
    if (manager == null) {
        throw new NullPointerException("manager is null");
    }
    if (consumer == null) {
        throw new NullPointerException("consumer is null");
    }
    applyConnection(
            manager,
            t -> {
                consumer.accept(t);
                return null;
            }
    );
}

static <U> void acceptConnection(
        final EntityManager manager,
        final BiConsumer<Connection, U> consumer, final U u) {
    if (manager == null) {
        throw new NullPointerException("manager is null");
    }
    if (consumer == null) {
        throw new NullPointerException("consumer is null");
    }
    acceptConnection(manager, t -> consumer.accept(t, u));
}
Run Code Online (Sandbox Code Playgroud)