Java 在纯 JPA 设置中获取数据库连接
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3493495/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Getting Database connection in pure JPA setup
提问by Jacob
We have a JPA application (using hibernate) and we need to pass a call to a legacy reporting tool that needs a JDBC database connection as a parameter. Is there a simple way to get access to the JDBC connection hibernate has setup?
我们有一个 JPA 应用程序(使用 hibernate),我们需要将调用传递给需要 JDBC 数据库连接作为参数的遗留报告工具。有没有一种简单的方法可以访问 hibernate 设置的 JDBC 连接?
采纳答案by Pascal Thivent
Where you want to get that connection is unclear. One possibility would be to get it from the underlying Hibernate Session
used by the EntityManager
. With JPA 1.0, you'll have to do something like this:
您想从哪里获得这种联系尚不清楚。一种可能性是从底层的Hibernate得到它Session
被使用EntityManager
。使用 JPA 1.0,您必须执行以下操作:
Session session = (Session)em.getDelegate();
Connection conn = session.connection();
Note that the getDelegate()
is not portable, the result of this method is implementation specific: the above code works in JBoss, for GlassFish you'd have to adapt it - have a look at Be careful while using EntityManager.getDelegate().
请注意,这getDelegate()
是不可移植的,此方法的结果是特定于实现的:上面的代码在 JBoss 中有效,对于 GlassFish,您必须对其进行调整 - 看看使用 EntityManager.getDelegate()时要小心。
In JPA 2.0, things are a bit better and you can do the following:
在 JPA 2.0 中,情况会好一些,您可以执行以下操作:
Connection conn = em.unwrap(Session.class).connection();
If you are running inside a container, you could also perform a lookup on the configured DataSource
.
如果您在容器内运行,您还可以对配置的DataSource
.
回答by Kees de Kooter
Hibernate uses a ConnectionProvider internally to obtain connections. From the hibernate javadoc:
Hibernate 在内部使用 ConnectionProvider 来获取连接。从休眠javadoc:
The ConnectionProvider interface is not intended to be exposed to the application. Instead it is used internally by Hibernate to obtain connections.
ConnectionProvider 接口不打算向应用程序公开。相反,它由 Hibernate 在内部使用以获取连接。
The more elegant way of solving this would be to create a database connection pool yourself and hand connections to hibernate and your legacy tool from there.
解决这个问题的更优雅的方法是自己创建一个数据库连接池,并从那里手动连接到休眠和遗留工具。
回答by Aneesh Vijendran
I ran into this problem today and this was the trick I did, which worked for me:
我今天遇到了这个问题,这是我做的技巧,对我有用:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("DAOMANAGER");
EntityManagerem = emf.createEntityManager();
org.hibernate.Session session = ((EntityManagerImpl) em).getSession();
java.sql.Connection connectionObj = session.connection();
Though not the best way but does the job.
虽然不是最好的方法,但可以完成工作。
回答by Dominik
As per the hibernate
docs here,
根据此处的hibernate
文档,
Connection connection()
Deprecated. (scheduled for removal in 4.x). Replacement depends on need; for doing direct JDBC stuff use doWork(org.hibernate.jdbc.Work) ...
连接连接()
已弃用。(计划在 4.x 中删除)。更换取决于需要;对于直接使用 JDBC 的东西,请使用 doWork(org.hibernate.jdbc.Work) ...
Use Hibernate Work API instead:
改用 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
}
});
回答by Luistar15
Since the code suggested by @Pascal is deprecated as mentioned by @Jacob, I found this another waythat works for me.
由于@Pascal 建议的代码如@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();
回答by Alberto Vazquez
If you are using JAVA EE 5.0, the best way to do this is to use the @Resource annotation to inject the datasource in an attribute of a class (for instance an EJB) to hold the datasource resource (for instance an Oracle datasource) for the legacy reporting tool, this way:
如果您使用的是 JAVA EE 5.0,最好的方法是使用 @Resource 批注将数据源注入类(例如 EJB)的属性中,以保存数据源资源(例如 Oracle 数据源)遗留报告工具,这样:
@Resource(mappedName="jdbc:/OracleDefaultDS") DataSource datasource;
Later you can obtain the connection, and pass it to the legacy reporting tool in this way:
稍后您可以获取连接,并通过以下方式将其传递给旧报告工具:
Connection conn = dataSource.getConnection();
回答by armando
if you use EclipseLink: You should be in a JPA transaction to access the Connection
如果您使用 EclipseLink:您应该在 JPA 事务中访问连接
entityManager.getTransaction().begin();
java.sql.Connection connection = entityManager.unwrap(java.sql.Connection.class);
...
entityManager.getTransaction().commit();
回答by uvperez
Here is a code snippet that works with Hibernate 4 based on Dominik's answer
这是一个基于 Dominik 的回答适用于 Hibernate 4 的代码片段
Connection getConnection() {
Session session = entityManager.unwrap(Session.class);
MyWork myWork = new MyWork();
session.doWork(myWork);
return myWork.getConnection();
}
private static class MyWork implements Work {
Connection conn;
@Override
public void execute(Connection arg0) throws SQLException {
this.conn = arg0;
}
Connection getConnection() {
return conn;
}
}
回答by aborskiy
Below is the code that worked for me. We use jpa 1.0, Apache openjpa implementation.
下面是对我有用的代码。我们使用 jpa 1.0,Apache openjpa 实现。
import java.sql.Connection;
import org.apache.openjpa.persistence.OpenJPAEntityManager;
import org.apache.openjpa.persistence.OpenJPAPersistence;
public final class MsSqlDaoFactory {
public static final Connection getConnection(final EntityManager entityManager) {
OpenJPAEntityManager openJPAEntityManager = OpenJPAPersistence.cast(entityManager);
Connection connection = (Connection) openJPAEntityManager.getConnection();
return connection;
}
}
回答by Jin Kwon
The word puredoesn't match to the word hibernate.
单词pure与单词hibernate不匹配。
EclipseLink
Eclipse链接
It's somewhat straightforward as described in above link.
如上面的链接所述,它有点简单。
- Note that the
EntityManager
must be joined to aTransaction
or theunwrap
method will returnnull
. (Not a good move at all.) - I'm not sure the responsibility of closing the connection.
- 请注意,
EntityManager
必须连接到 aTransaction
否则该unwrap
方法将返回null
。(根本不是一个好举动。) - 我不确定关闭连接的责任。
// --------------------------------------------------------- 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");
}
Hibernate
休眠
It should be, basically, done with following codes.
基本上,应该使用以下代码完成。
// using vendor specific APIs
final Session session = (Session) manager.unwrap(Session.class);
//return session.doReturningWork<R>(function::apply);
return session.doReturningWork(new ReturningWork<R>() {
@Override public R execute(final Connection connection) {
return function.apply(connection);
}
});
Well, we (at least I) might don't want any vendor-specific dependencies. Proxycomes in rescue.
好吧,我们(至少我)可能不想要任何特定于供应商的依赖项。代理来救援。
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");
}
OpenJPA
开放式JPA
I'm not sure OpenJPA already serves a way using unwrap(Connection.class)
but can be done with the way described in one of above links.
我不确定 OpenJPA 是否已经提供了一种使用方式,unwrap(Connection.class)
但可以使用上述链接之一中描述的方式来完成。
It's not clear the responsibility of closing the connection. The document (one of above links) seems saying clearly but I'm not good at English.
目前尚不清楚关闭连接的责任。该文件(上述链接之一)似乎说得很清楚,但我不擅长英语。
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");
}