session.connection () im Ruhezustand veraltet?

80

Wir müssen in der Lage sein, die zugehörige java.sql.ConnectionSitzung im Ruhezustand abzurufen. Es funktioniert keine andere Verbindung, da diese Verbindung möglicherweise einer laufenden Transaktion zugeordnet ist.

Wie soll ich das tun, wenn session.connection () jetzt veraltet ist?

TraderJoeChicago
quelle
Falls jemand mehr darüber lesen möchte: hibernate.onjira.com/browse/HHH-2603
WW.
9
Einer der vielen Gründe, sich von diesem schrecklichen Rahmen namens Hibernate fernzuhalten. Es ist Zeit, dass es für immer schlafen geht, wie der Name schon sagt.
Chrisapotek
2
@chrisapotek Du magst Hibernate nicht ... hast du Alternativen oder schreibst du das ganze Persistenz-Zeug von Hand?
Emaborsa
1
Wie wäre es mit Mybatis?
Geoffrey Ritchey

Antworten:

86

Sie müssen jetzt die Arbeits-API verwenden:

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

Oder in Java 8+:

session.doWork(connection -> doSomething(connection)); 
KeatsPeeks
quelle
1
Ich mag es nicht, veraltete Sachen zu verwenden, aber ich denke, dies ist ein guter Grund, damit zu beginnen. Aber ich wusste nichts über die Arbeits-API. Vielen Dank.
TraderJoeChicago
1
Beeindruckend. Ich verwende Hibernate 3.2.7.ga, aber meine org.hibernate.Session hat KEINE doWork-Methode. Das ist großartig!
TraderJoeChicago
25
igitt das ist hässlich. Die Leute werden immer die rohe Verbindung für etwas brauchen - sie sollten es einfach machen.
Peter
9
SessionImpl sessionImpl = (SessionImpl) session; Connection conn = sessionImpl.connection();Sie können das Verbindungsobjekt dann überall dort verwenden, wo Sie es in diesem Code benötigen, und nicht nur auf eine kleine Methode beschränken.
Simon Mbatia
2
Noch kürzer in Java8 - session.doWork(this::doSomething). Wenn Sie ein Ergebnis zurückgeben möchten, verwenden Sie doReturningWork ()
Optio
22

Wenn session.connect()es jetzt veraltet ist, wie soll ich das machen?

Sie müssen Session#doWork(Work)und die WorkAPI verwenden, wie im Javadoc erwähnt:

connection()
     Veraltet. (geplant für die Entfernung in 4.x). Der Austausch hängt vom Bedarf ab. für die direkte Verwendung von JDBC-Inhalten doWork(org.hibernate.jdbc.Work); zum Öffnen einer "temporären Sitzung" verwenden (TBD).

Sie haben einige Zeit vor Hibernate 4.x, aber die Verwendung einer veralteten API sieht irgendwie so aus:

Alt-Text:) :)

Update: Laut RE: [hibernate-dev] Verbindungs-Proxy auf der Hibernate-dev-Liste scheint es, dass die ursprüngliche Absicht der Ablehnung darin bestand, die Verwendung von zu verhindern, Session#connection()da es als "schlechte" API angesehen wurde / wird, aber es sollte zu dieser Zeit bleiben. Ich denke, sie haben ihre Meinung geändert ...

Pascal Thivent
quelle
2
Mein Javadoc hier ist etwas anders als deins. Nur ein bisschen weniger klar: Wird durch ein SPI ersetzt, um Arbeiten an der Verbindung auszuführen. geplant für die Entfernung in 4.x. Ihr JavaDoc sagt alles. Dieser JavaDoc sagt nichts.
TraderJoeChicago
@ Sergio In der Tat. Aber wenn ich darf, sollten Sie wichtige Dinge wie die Hibernate-Version erwähnen, die Sie in Ihrer Frage verwenden. Ihre Version ist ziemlich alt (das Javadoc Session#connection()in Hibernate Core 3.3 erwähnt die Alternative) und das können Leser normalerweise nicht erraten.
Pascal Thivent
@Pascal Version 3.2.7.ga ist die neueste Version, die ich auf Maven finden konnte. GroupId = org.hibernate und ArtefaktId = Ruhezustand. Ich frage mich, ob Maven die neueste Version bereitstellen kann oder ob Sie nur das Glas kopieren und Maven ignorieren müssen.
TraderJoeChicago
@Sergio Das liegt daran, dass Sie das alte monolithische Glas ( hibernate) verwenden und nicht hibernate-coredas, das neuere Versionen hat. Und für ultimative Versionen (3.5.x) sind sie im JBoss Nexus-Repository verfügbar .
Pascal Thivent
1
@Pascal Danke! Ein großes Problem ist, dass ich die Verbindung weitergeben muss. Wenn Hibernate mir die Verbindung nicht bereitstellen kann, ist sie schlecht. Ich muss diese Verbindung auf andere Weise herstellen. Ich denke, wer diese Idee hatte, die Verbindungsmethode abzulehnen, sollte noch einmal darüber nachdenken.
TraderJoeChicago
12

Versuche dies

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

Tatsächlich gibt getSession den Typ der Sitzungsschnittstelle zurück. Sie sollten sehen, was die ursprüngliche Klasse für die Sitzung ist. Geben Sie cast in die ursprüngliche Klasse ein und erhalten Sie die Verbindung.

VIEL GLÜCK!

Mohammad Hosseini
quelle
1
❤️ uuuuu so frustrierend, dass dies notwendig ist - ich versuche, meine App so einzurichten, dass schreibgeschützte Verbindungen hergestellt werden, um sie auf Lesereplikate zu verteilen. Vielen Dank.
Sam Berry
1
Warum hat das nicht mehr positive Stimmen? Gibt es einen Grund, warum dies nicht getan werden sollte? Funktioniert perfekt für mich.
@tilper SessionImplbefindet sich in einem internen Paket von Hibernate (daher nicht zur Verwendung vorgesehen) und dies ist auch eine Abhängigkeit von der tatsächlichen Implementierung. Außerdem können Sie die Sitzung in Ihren Tests nicht einfach verspotten, wenn Sie sie wirken.
Vic
9

Es gibt noch eine andere Option, an der immer noch viele Casts beteiligt sind, aber zumindest muss sie nicht reflektiert werden, wodurch Sie die Überprüfung der Kompilierungszeit zurückerhalten können:

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

Sie könnten das natürlich mit ein paar instanceofÜberprüfungen noch "schöner" machen , aber die obige Version funktioniert für mich.

Stefan Haberl
quelle
9

Hier ist eine Möglichkeit, dies in Hibernate 4.3 zu tun, und es ist nicht veraltet:

  Session session = entityManager.unwrap(Session.class);
  SessionImplementor sessionImplementor = (SessionImplementor) session;
  Connection conn = sessionImplementor.getJdbcConnectionAccess().obtainConnection();
Louis-Félix
quelle
1
Ist es sicher , konvertieren sessionzu SessionImplementor?
Macemers
@DerekY, ich weiß, das ist alt, aber ich beschäftige mich jetzt nur damit. Und ja, das ist es. Alle Session-Implementierungen sind auch irgendwie SessionImplementors.
Reginaldo Santos
9

Das benutze ich und arbeite für mich. Downcast das Session-Objekt in ein SessionImpl und erhalte das Verbindungsobjekt einfach:

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

Wo sessionist der Name Ihres Sitzungsobjekts im Ruhezustand?

Simon Mbatia
quelle
8

connection()wurde nur auf der Schnittstelle veraltet. Es ist noch verfügbar am SessionImpl. Sie können das tun, was der Frühling tut, und das einfach so nennen.

Hier ist der Code aus dem HibernateJpaDialectFrühjahr 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);
        }
    }
Patrick
quelle
15
Dies ist die Art von Dingen, die ein fantastischer Ruhezustand Sie dazu bringt. Nur wenige Frameworks sind so schlecht wie Hibernate.
Chrisapotek
8

Ich habe diesen Artikel gefunden

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

Es hat mir geholfen.

PETRo
quelle
6

Mit Hibernate> = 5.0 erhalten Sie Folgendes Connection:

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

Versuchen Sie für Hibenat 4.3 Folgendes:

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
quelle
1

Versuche dies:

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
quelle
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
quelle
0

Hier ist eine Java 8-Methode, um die Connectionvon einem verwendeten zurückzugeben, EntityManagerohne tatsächlich etwas damit zu tun:

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 Chambers
quelle