86

We need to be able to get the associated java.sql.Connection of a hibernate session. No other connection will work, as this connection may be associated with a running transaction.

If session.connection() is now deprecated, how am I supposed to do that?

4
  • In case anyone wants to read more about this: hibernate.onjira.com/browse/HHH-2603
    – WW.
    Commented Mar 27, 2012 at 5:29
  • 9
    One of the many reasons to stay away from this awful framework called Hibernate. It is time for it to go sleep forever as the name implies. Commented May 1, 2012 at 22:58
  • 2
    @chrisapotek You don't like Hibernate...do you have any alternatives or do you write all the persistence stuff by hand?
    – Emaborsa
    Commented Jul 25, 2014 at 6:43
  • 1
    How about mybatis? Commented Jan 22, 2020 at 17:47

14 Answers 14

93

You now have to use the Work API:

session.doWork(connection -> doSomething(connection)); 

Or, in Java < 8 :

session.doWork(
    new Work() {
        public void execute(Connection connection) throws SQLException 
        { 
            doSomething(connection); 
        }
    }
);
9
  • 1
    I don't like using deprecated stuff but i guess this is a good reason to start using it. But I did not know about the Work API. Thanks very much. Commented Aug 19, 2010 at 22:23
  • 1
    Wow. I am using Hibernate 3.2.7.ga but my org.hibernate.Session does NOT have any doWork method. That's great! Commented Aug 20, 2010 at 0:48
  • 27
    yuck that is ugly. People are always going to need the raw connection for something - they should make it easy.
    – Peter
    Commented Oct 31, 2011 at 17:42
  • 11
    SessionImpl sessionImpl = (SessionImpl) session; Connection conn = sessionImpl.connection(); You can then use the connection object anywhere elese you need it in that code not just confined to a small method. Commented May 17, 2015 at 9:57
  • 2
    Even more shorter in Java8 - session.doWork(this::doSomething). If you want to return a result - use doReturningWork()
    – Optio
    Commented Jun 14, 2017 at 9:14
22

If session.connect() is now deprecated, how am I supposed to do that?

You have to use Session#doWork(Work) and the Work API, as mentioned in the Javadoc:

connection()
     Deprecated. (scheduled for removal in 4.x). Replacement depends on need; for doing direct JDBC stuff use doWork(org.hibernate.jdbc.Work); for opening a 'temporary Session' use (TBD).

You have some time before Hibernate 4.x but, well, using a deprecated API somehow looks like this:

alt text:)

Update: According to RE: [hibernate-dev] Connection proxying on the hibernate-dev list, it seems that the initial intention of the deprecation was to discourage the use of Session#connection() because it was/is considered as a "bad" API, but it was supposed to stay at that time. I guess they changed their mind...

6
  • 2
    My Javadoc here is slightly different than yours. Just a little less clear: To be replaced with a SPI for performing work against the connection; scheduled for removal in 4.x. Your JavaDoc says it all. This JavaDoc says nothing. Commented Aug 20, 2010 at 0:43
  • @Sergio Indeed. But if I may, you should mention important things like the Hibernate version you're using in your question. Your version is pretty old (the javadoc of Session#connection() in Hibernate Core 3.3 mentions the alternative) and that's typically something readers can't guess. Commented Aug 20, 2010 at 2:28
  • @Pascal Version 3.2.7.ga is the latest I could find on Maven. GroupId = org.hibernate and artifactId = hibernate. I wonder if Maven can provide the latest version or if you just need to copy the jar and ignore maven. Commented Aug 20, 2010 at 11:10
  • @Sergio That's because you're using the old monolithic jar (hibernate) and not hibernate-core which has more recent versions. And for ultimate versions (3.5.x), they are in available in the JBoss Nexus repository. Commented Aug 20, 2010 at 13:46
  • 1
    @Pascal Thanks! One big problem is that I need to pass the connection around, so if Hibernate will not be able to provide me with its connection then it will be bad. I will need to get this connection some way else. I think whoever had this idea of deprecating the connection method should think again. Commented Aug 25, 2010 at 14:29
12

Try This

((SessionImpl)getSession()).connection()

Actuly getSession returns Session Interface type, you should see what is the original class for the session, type cast to the original class then get the connection.

GOOD LUCK!

4
  • 1
    ❤️ uuuuu so frustrating this is necessary - trying to get my app setup to set readonly connections in order to distribute across read replicas. Thanks.
    – Sam Berry
    Commented Dec 5, 2017 at 15:09
  • 1
    Why doesn't this have more upvotes? Is there some reason this shouldn't be done? Works perfectly for me.
    – user6096242
    Commented Aug 1, 2018 at 15:12
  • @tilper SessionImpl is in an internal package of Hibernate (so not intended to be used) and also that is a dependency on actual implementation. Also you cannot mock the session in your tests easily, when you cast it.
    – Vic
    Commented May 31, 2019 at 11:28
  • My question is what happens when you want the connection "free", and you achieve that by returning the connection passed from doReturningWork ... would that not essentially be the same as getConnection() ?
    – mjs
    Commented Feb 5, 2023 at 15:03
10

Here is a way to do it in Hibernate 4.3, and it is not deprecated:

  Session session = entityManager.unwrap(Session.class);
  SessionImplementor sessionImplementor = (SessionImplementor) session;
  Connection conn = sessionImplementor.getJdbcConnectionAccess().obtainConnection();
2
  • 1
    Is it safe to convert session to SessionImplementor?
    – macemers
    Commented Sep 11, 2015 at 8:17
  • @DerekY, I know this is old, but just dealing with it now. And YES, it is. All Session implementations are also SessionImplementor's somehow. Commented Sep 27, 2017 at 15:50
10

This is what I use and works for me. Downcast the Session object into a SessionImpl and get the connection object easily:

SessionImpl sessionImpl = (SessionImpl) session;
Connection conn = sessionImpl.connection();

where session is the name of your Hibernate session object.

1
  • My question is what happens when you want the connection "free", and you achieve that by returning the connection passed from doReturningWork ... would that not essentially be the same as getConnection() ?
    – mjs
    Commented Feb 5, 2023 at 15:03
9

There's another option with still a lot of casts involved, but at least it doesn't need reflection, which will give you back compile time checking:

public Connection getConnection(final EntityManager em) {
  HibernateEntityManager hem = (HibernateEntityManager) em;
  SessionImplementor sim = (SessionImplementor) hem.getSession();
  return sim.connection();
}

You could of course make that even "prettier" with a few instanceof checks, but the version above works for me.

9

I found this article

package com.varasofttech.client;

import java.sql.Connection;
import java.sql.SQLException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.SessionImpl;
import org.hibernate.jdbc.ReturningWork;
import org.hibernate.jdbc.Work;

import com.varasofttech.util.HibernateUtil;

public class Application {

public static void main(String[] args) {

    // Different ways to get the Connection object using Session

    SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
    Session session = sessionFactory.openSession();

    // Way1 - using doWork method
    session.doWork(new Work() {
        @Override
        public void execute(Connection connection) throws SQLException {
            // do your work using connection
        }

    });

    // Way2 - using doReturningWork method
    Connection connection = session.doReturningWork(new ReturningWork<Connection>() {
        @Override
        public Connection execute(Connection conn) throws SQLException {
            return conn;
        }
    });

    // Way3 - using Session Impl
    SessionImpl sessionImpl = (SessionImpl) session;
    connection = sessionImpl.connection();
    // do your work using connection

    // Way4 - using connection provider
    SessionFactoryImplementor sessionFactoryImplementation = (SessionFactoryImplementor) session.getSessionFactory();
    ConnectionProvider connectionProvider = sessionFactoryImplementation.getConnectionProvider();
    try {
        connection = connectionProvider.getConnection();
        // do your work using connection
    } catch (SQLException e) {
        e.printStackTrace();
    }
}
}

It helped me.

8

connection() was just deprecated on the interface. It is still available on SessionImpl. You can do what Spring does and just call that one.

Here is the code from HibernateJpaDialect in Spring 3.1.1

public Connection getConnection() {
        try {
            if (connectionMethod == null) {
                // reflective lookup to bridge between Hibernate 3.x and 4.x
                connectionMethod = this.session.getClass().getMethod("connection");
            }
            return (Connection) ReflectionUtils.invokeMethod(connectionMethod, this.session);
        }
        catch (NoSuchMethodException ex) {
            throw new IllegalStateException("Cannot find connection() method on Hibernate session", ex);
        }
    }
1
  • 15
    This is the kind of things that awesome Hibernate make you do. Few frameworks are so bad as Hibernate. Commented May 1, 2012 at 23:01
7

With Hibernate >= 5.0 you can get the Connection like this:

Connection c = sessionFactory.
getSessionFactoryOptions().getServiceRegistry().
getService(ConnectionProvider.class).getConnection();
3

For hibenate 4.3 try this:

public static Connection getConnection() {
        EntityManager em = <code to create em>;
        Session ses = (Session) em.getDelegate();
        SessionFactoryImpl sessionFactory = (SessionFactoryImpl) ses.getSessionFactory();
        try{
            connection = sessionFactory.getConnectionProvider().getConnection();
        }catch(SQLException e){
            ErrorMsgDialog.getInstance().setException(e);
        }
        return connection;
    }
1

Try this:

public Connection getJavaSqlConnectionFromHibernateSession() {

    Session session = this.getSession();
    SessionFactoryImplementor sessionFactoryImplementor = null;
    ConnectionProvider connectionProvider = null;
    java.sql.Connection connection = null;
    try {
        sessionFactoryImplementor = (SessionFactoryImplementor) session.getSessionFactory();
        connectionProvider = (ConnectionProvider) sessionFactoryImplementor.getConnectionProvider().getConnection();
        connection = connectionProvider.getConnection();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return connection;
}
0
    Connection conn = null;
    PreparedStatement preparedStatement = null;
    try {
        Session session = (org.hibernate.Session) em.getDelegate();
        SessionFactoryImplementor sfi = (SessionFactoryImplementor) session.getSessionFactory();
        ConnectionProvider cp = sfi.getConnectionProvider();
        conn = cp.getConnection();
        preparedStatement = conn.prepareStatement("Select id, name from Custumer");
        ResultSet rs = preparedStatement.executeQuery();
        while (rs.next()) {
            System.out.print(rs.getInt(1));
            System.out.println(rs.getString(2));
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (preparedStatement != null) {
            preparedStatement.close();
        }
        if (conn != null) {
            conn.close();
        }
    }
0

Here is a Java 8 method to return the Connection used by an EntityManager without actually doing anything with it yet:

private Connection getConnection(EntityManager em) throws SQLException {
    AtomicReference<Connection> atomicReference = new AtomicReference<Connection>();
    final Session session = em.unwrap(Session.class);
    session.doWork(connection -> atomicReference.set(connection));
    return atomicReference.get();
}
0

If you need a return value from inside the lambda, don't overlook doReturningWork()

try {
  return session.doReturningWork(connection -> {
    try (CallableStatement cs = connection.prepareCall(...)) {
      cs.doSomethingPseudoMethod();
      cs.executeUpdate();
      return cs;
    }
  });
} catch (SQLException sqlException) {
  ...
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.