session.connection () obsoleto en Hibernate?

80

Necesitamos poder obtener el asociado java.sql.Connectionde una sesión de hibernación. Ninguna otra conexión funcionará, ya que esta conexión puede estar asociada con una transacción en ejecución.

Si session.connection () ahora está en desuso, ¿cómo se supone que debo hacer eso?

TraderJoeChicago
fuente
En caso de que alguien quiera leer más sobre esto: hibernate.onjira.com/browse/HHH-2603
WW.
9
Una de las muchas razones para mantenerse alejado de este horrible marco llamado Hibernate. Es hora de que se duerma para siempre, como su nombre lo indica.
chrisapotek
2
@chrisapotek No te gusta Hibernate ... ¿tienes alguna alternativa o escribes todo el material de persistencia a mano?
Emaborsa
1
¿Qué tal mybatis?
Geoffrey Ritchey

Respuestas:

86

Ahora tienes que usar la API de trabajo:

session.doWork(
    new Work() {
        public void execute(Connection connection) throws SQLException 
        { 
            doSomething(connection); 
        }
    }
);

O, en Java 8+:

session.doWork(connection -> doSomething(connection)); 
KeatsPeeks
fuente
1
No me gusta usar cosas obsoletas, pero supongo que esta es una buena razón para comenzar a usarlas. Pero no sabía nada de la API de trabajo. Muchas gracias.
TraderJoeChicago
1
Guau. Estoy usando Hibernate 3.2.7.ga pero mi org.hibernate.Session NO tiene ningún método doWork. ¡Eso es genial!
TraderJoeChicago
25
puaj eso es feo. La gente siempre va a necesitar la conexión en bruto para algo; deberían facilitarlo.
Peter
9
SessionImpl sessionImpl = (SessionImpl) session; Connection conn = sessionImpl.connection();Luego, puede usar el objeto de conexión en cualquier lugar donde lo necesite en ese código, no solo confinado a un método pequeño.
Simon Mbatia
2
Aún más corto en Java8 - session.doWork(this::doSomething). Si desea devolver un resultado, use doReturningWork ()
Optio
22

Si session.connect()ahora está en desuso, ¿cómo se supone que debo hacer eso?

Tienes que usar Session#doWork(Work)y la WorkAPI, como se menciona en el Javadoc:

connection()
     Obsoleto. (programado para su eliminación en 4.x). El reemplazo depende de la necesidad; para hacer uso directo de material JDBC doWork(org.hibernate.jdbc.Work); para abrir un uso de 'sesión temporal' (TBD).

Tiene algo de tiempo antes de Hibernate 4.x pero, bueno, usar una API obsoleta de alguna manera se ve así:

texto alternativo:)

Actualización: De acuerdo con RE: [hibernate-dev] Conexión proxy en la lista de hibernate-dev, parece que la intención inicial de la desaprobación era desalentar el uso de Session#connection()porque era / se considera una API "mala", pero se suponía que debía quedarse en ese momento. Supongo que cambiaron de opinión ...

Pascal Thivent
fuente
2
Mi Javadoc aquí es ligeramente diferente al tuyo. Solo un poco menos claro: para ser reemplazado por un SPI para realizar trabajos contra la conexión; programado para su eliminación en 4.x. Su JavaDoc lo dice todo. Este JavaDoc no dice nada.
TraderJoeChicago
@Sergio De hecho. Pero si me lo permite, debería mencionar cosas importantes como la versión de Hibernate que está usando en su pregunta. Su versión es bastante antigua (el javadoc de Session#connection()en Hibernate Core 3.3 menciona la alternativa) y eso es típicamente algo que los lectores no pueden adivinar.
Pascal Thivent
@Pascal Versión 3.2.7.ga es la última que pude encontrar en Maven. GroupId = org.hibernate y artifactId = hibernate. Me pregunto si Maven puede proporcionar la última versión o si solo necesita copiar el archivo jar e ignorar a Maven.
TraderJoeChicago
@Sergio Eso es porque estás usando el antiguo jar monolítico ( hibernate) y no el hibernate-coreque tiene versiones más recientes. Y para las últimas versiones (3.5.x), están disponibles en el repositorio de JBoss Nexus .
Pascal Thivent
1
@Pascal ¡Gracias! Un gran problema es que necesito pasar la conexión, por lo que si Hibernate no puede proporcionarme su conexión, será mala. Necesitaré obtener esta conexión de alguna otra manera. Creo que quienquiera que haya tenido la idea de desaprobar el método de conexión debería pensarlo de nuevo.
TraderJoeChicago
12

Prueba esto

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

Actuly getSession devuelve el tipo de interfaz de sesión, debería ver cuál es la clase original para la sesión, escriba cast a la clase original y luego obtenga la conexión.

¡BUENA SUERTE!

Mohammad Hosseini
fuente
1
❤️ uuuuu, esto es tan frustrante que es necesario: intentar configurar mi aplicación para establecer conexiones de solo lectura para distribuir entre réplicas de lectura. Gracias.
Sam Berry
1
¿Por qué esto no tiene más votos a favor? ¿Hay alguna razón por la que esto no debería hacerse? Funciona perfectamente para mi.
@tilper SessionImplestá en un paquete interno de Hibernate (por lo que no está destinado a ser utilizado) y también depende de la implementación real. Además, no puede burlarse fácilmente de la sesión en sus pruebas cuando la lanza.
Vic
9

Hay otra opción en la que todavía hay muchos cambios involucrados, pero al menos no necesita reflexión, lo que le devolverá la verificación del tiempo de compilación:

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

Por supuesto, podría hacerlo aún más "bonito" con algunas instanceofcomprobaciones, pero la versión anterior funciona para mí.

Stefan Haberl
fuente
9

Aquí hay una forma de hacerlo en Hibernate 4.3, y no está en desuso:

  Session session = entityManager.unwrap(Session.class);
  SessionImplementor sessionImplementor = (SessionImplementor) session;
  Connection conn = sessionImplementor.getJdbcConnectionAccess().obtainConnection();
Louis-Félix
fuente
1
¿Es seguro convertir sessiona SessionImplementor?
macemers
@DerekY, sé que esto es viejo, pero estoy tratando con eso ahora. Y SI, lo es. Todas las implementaciones de Session también son de algún modo de SessionImplementor.
Reginaldo Santos
9

Esto es lo que uso y me funciona. Downcast el objeto Session en un SessionImpl y obtenga el objeto de conexión fácilmente:

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

donde sessiones el nombre de su objeto de sesión de Hibernate.

Simón Mbatia
fuente
8

connection()estaba en desuso en la interfaz. Todavía está disponible el SessionImpl. Puedes hacer lo que hace Spring y simplemente llamar a eso.

Aquí está el código de HibernateJpaDialectSpring 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);
        }
    }
Patricio
fuente
15
Este es el tipo de cosas que la increíble Hibernate te hace hacer. Pocos marcos son tan malos como Hibernate.
chrisapotek
8

Encontre este articulo

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();
    }
}
}

Me ayudó.

PETRo
fuente
6

Con Hibernate> = 5.0 puede obtener lo Connectionsiguiente:

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

Para hibenate 4.3 intente esto:

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;
    }
shcherbak
fuente
1

Prueba esto:

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;
}
segaurav
fuente
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();
        }
    }
user2209871
fuente
0

Aquí hay un método de Java 8 para devolver el Connectionusado por un EntityManagersin hacer nada con él todavía:

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();
}
Steve Cámaras
fuente