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?
13 Answers
As per the hibernate
docs here,
Connection connection()
Deprecated. (scheduled for removal in 4.x). Replacement depends on need; for doing direct JDBC stuff use doWork(org.hibernate.jdbc.Work) ...
Use Hibernate Work API instead:
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
}
});

- 1,850
- 19
- 40

- 669
- 5
- 2
-
Obtaining access to the connection this way works for me... but I've problems using `conn.rollback(savepoint)` as described in https://stackoverflow.com/q/45672431/173689 – Daniel Bleisteiner Aug 14 '17 at 13:08
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:
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().
In JPA 2.0, things are a bit better and you can do the following:
Connection conn = em.unwrap(Session.class).connection();
If you are running inside a container, you could also perform a lookup on the configured DataSource
.

- 562,542
- 136
- 1,062
- 1,124
-
2When I do either of these I get a deprecation warning. I can live with it if a have to but its a bit annoying (: Its not like I want to have to do this, its just pragmatically the simplest way to get things going. – Jay Aug 17 '10 at 12:03
-
8Yes, `connection()` is deprecated in Hibernate 3.x, they are changing the API (and I don't think you'll like the new API for your use case). But the change is planned for Hibernate 4.x, this gives you some time. – Pascal Thivent Aug 17 '10 at 13:58
-
5This doesn't seem to be viable using EclipseLink. you can't get the connection from the Session. It seems you may be able to unwrap the connection though - `Connection conn = em.unwrap(Connection.class)`. Doubt that's portable either though... – wmorrison365 Mar 25 '13 at 11:25
-
do we need to close this connection when we finish method call? or does the container know what to do? – Thang Pham Jul 25 '17 at 10:22
-
The link for the blog is now dead. What it used to have? – Victor Stafusa - BozoNaCadeia Oct 31 '17 at 17:39
-
FWIW, for those using EclipseLink like me, the following worked Session session = em.unwrap(Session.class); session.executeNonSelectingSQL("SQL CODE..."); – Thomas Nov 30 '21 at 07:56
-
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:
@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();

- 53,861
- 28
- 137
- 147

- 331
- 3
- 2
-
4+1 This is the only correct solution, I think. The others rely on non-portable, product-specific (Hibernate, EclipseLink) code. – Rogério Aug 02 '16 at 19:30
-
Good solution, and kudos for thinking outside the (question's) box. BTW, if you use Spring instead of Java EE alias Jakarta EE, a similar solution works: Configure your datasource as a Spring bean (which you probably should do anyway), and inject it. – sleske Oct 30 '18 at 09:10
-
You need to be careful with this if you are also using JPA in the same request. You end up getting 2 connections which can cause lockup if the connection pool doesn't have any free. The thread is holding one connection and stuck trying to get another. – David Tinker Feb 09 '23 at 07:13
if you use EclipseLink: You should be in a JPA transaction to access the Connection
entityManager.getTransaction().begin();
java.sql.Connection connection = entityManager.unwrap(java.sql.Connection.class);
...
entityManager.getTransaction().commit();

- 301
- 3
- 2
-
1Not the case then it comes to Hibernate, works only with EclipseLink. – Jin Kwon Apr 21 '17 at 02:37
-
Not sure if this is relevant, but as of Jul2019, using eclipselink 2.5.0 and querydsl 4.2.1, the proposed unwrap(Connection.class) approach returns null in my own project. Possible workaround: create the needed JPASQLQuery and pass the existing entityManager as parameter (see querydsl.com/static/querydsl/4.2.1/apidocs/com/querydsl/jpa/sql/…) – Repoker Jul 10 '19 at 10:03
-
This worked for me. I'm deploying my application to a Java EE application server, but I wanted to use standalone JPA/EclipseLink in JUnit. `unwrap(Connection.class)` was returning null in JUnit, but if I start the transaction in the `@BeforeEach` method it works. – DavidS Dec 02 '19 at 22:54
Hibernate 4 / 5:
Session session = entityManager.unwrap(Session.class);
session.doWork(connection -> doSomeStuffWith(connection));

- 9,436
- 14
- 75
- 148
Since the code suggested by @Pascal is deprecated as mentioned by @Jacob, I found this another way that works for me.
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();
-
6`getConnectionProvider()` is deprecated in `org.hibernate.engine.spi.SessionFactoryImplementor` – slartidan May 07 '15 at 13:23
-
4
The word pure doesn't match to the word hibernate.
EclipseLink
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.
// --------------------------------------------------------- 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. Proxy comes 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
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.
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");
}

- 20,295
- 14
- 115
- 184
I am a little bit new to Spring Boot, I have needing the Connection object to send it to Jasperreport also, after trying the different answers in this post, this was only useful for me and, I hope it helps someone who is stuck at this point.
@Repository
public class GenericRepository {
private final EntityManager entityManager;
@Autowired
public GenericRepository(EntityManager entityManager, DataSource dataSource) {
this.entityManager = entityManager;
}
public Connection getConnection() throws SQLException {
Map<String, Object> properties = entityManager.getEntityManagerFactory().getProperties();
HikariDataSource dataSource = (HikariDataSource) properties.get("javax.persistence.nonJtaDataSource");
return dataSource.getConnection();
}
}

- 145
- 2
- 12
Hibernate uses a ConnectionProvider internally to obtain connections. From the hibernate javadoc:
The ConnectionProvider interface is not intended to be exposed to the application. Instead it is used internally by Hibernate to obtain connections.
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.

- 7,078
- 5
- 38
- 45
-
but it is exposed to the application... (: I think that might be the answer. – Jay Aug 16 '10 at 14:18
-
1Be careful with this approach if you are using the OpenEntityManagerInViewFilter or related classes. Requiring multiple connections to service a request can reach deadlock under the wrong conditions. – Casey Watson Mar 10 '13 at 15:20
Below is the code that worked for me. We use jpa 1.0, Apache openjpa implementation.
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;
}
}

- 1,337
- 2
- 10
- 12
I'm using a old version of Hibernate (3.3.0) with a newest version of OpenEJB (4.6.0). My solution was:
EntityManagerImpl entityManager = (EntityManagerImpl)em.getDelegate();
Session session = entityManager.getSession();
Connection connection = session.connection();
Statement statement = null;
try {
statement = connection.createStatement();
statement.execute(sql);
connection.commit();
} catch (SQLException e) {
throw new RuntimeException(e);
}
I had an error after that:
Commit can not be set while enrolled in a transaction
Because this code above was inside a EJB Controller (you can't commit
inside a transaction). I annotated the method with @TransactionAttribute(value = TransactionAttributeType.NOT_SUPPORTED)
and the problem was gone.

- 17,757
- 11
- 115
- 164
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.

- 11
- 1
Here is a code snippet that works with Hibernate 4 based on Dominik's answer
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;
}
}

- 21
- 3
-
-
This only get the reference to connection, after you use getConnection you could do custom jdbc code and then close it – uvperez Oct 06 '16 at 00:48