session.connection () przestarzałe w Hibernate?


80

Musimy być w stanie uzyskać skojarzenie java.sql.Connectionz sesją hibernacji. Żadne inne połączenie nie będzie działać, ponieważ to połączenie może być powiązane z uruchomioną transakcją.

Jeśli session.connection () jest teraz przestarzała, jak mam to zrobić?


Gdyby ktoś chciał poczytać więcej na ten temat: hibernate.onjira.com/browse/HHH-2603
WW.

9
Jeden z wielu powodów, dla których warto trzymać się z daleka od tego okropnego frameworka zwanego Hibernate. Nadszedł czas, aby zasnął na zawsze, jak sugeruje nazwa.
chrisapotek

2
@chrisapotek Nie lubisz Hibernate'a ... czy masz jakieś alternatywy, czy też piszesz ręcznie wszystkie rzeczy związane z wytrwałością?
Emaborsa

1
A co z mybatis?
Geoffrey Ritchey

Odpowiedzi:


86

Teraz musisz użyć Work API:

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

Lub w Javie 8+:

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

1
Nie lubię używać przestarzałych rzeczy, ale myślę, że jest to dobry powód, aby zacząć ich używać. Ale nie wiedziałem o Work API. Dziękuję bardzo.
TraderJoeChicago

1
Łał. Używam Hibernate 3.2.7.ga, ale moja org.hibernate.Session NIE ma żadnej metody doWork. To wspaniale!
TraderJoeChicago

25
fuj, to jest brzydkie. Ludzie zawsze będą potrzebować surowego połączenia - powinni to ułatwić.
Peter

9
SessionImpl sessionImpl = (SessionImpl) session; Connection conn = sessionImpl.connection();Następnie możesz użyć obiektu connection wszędzie tam, gdzie potrzebujesz go w tym kodzie, a nie tylko ograniczając się do małej metody.
Simon Mbatia,

2
Jeszcze krótszy w Java8 - session.doWork(this::doSomething). Jeśli chcesz zwrócić wynik - użyj doReturningWork ()
Optio

22

Jeśli session.connect()jest teraz przestarzały, jak mam to zrobić?

Musisz użyć Session#doWork(Work)i WorkAPI, jak wspomniano w Javadoc:

connection()
     Przestarzałe. (planowane do usunięcia w 4.x). Wymiana zależy od potrzeb; za bezpośrednie wykorzystanie rzeczy JDBC doWork(org.hibernate.jdbc.Work); do otwarcia użycia „tymczasowej sesji” (do ustalenia).

Masz trochę czasu przed Hibernate 4.x, ale cóż, używanie przestarzałego API wygląda jakoś tak:

tekst alternatywny:)

Aktualizacja: Według RE: [hibernate-dev] Połączenie proxy na liście hibernate-dev wydaje się, że początkowym zamiarem wycofania było zniechęcenie do używania, Session#connection()ponieważ był / jest uważany za „zły” interfejs API, ale miał w tym czasie zostać. Chyba zmienili zdanie ...


2
Mój Javadoc tutaj jest nieco inny niż twój. Tylko trochę mniej jasne: do zastąpienia przez SPI do wykonywania pracy przeciwko połączeniu; zaplanowane do usunięcia w 4.x. Twoja JavaDoc mówi wszystko. Ten dokument JavaDoc nic nie mówi.
TraderJoeChicago

@Sergio Rzeczywiście. Ale jeśli mogę, powinieneś wspomnieć o ważnych rzeczach, takich jak wersja Hibernacji, której używasz w swoim pytaniu. Twoja wersja jest dość stara (javadoc Session#connection()w Hibernate Core 3.3 wspomina o alternatywie) i zazwyczaj jest to coś, czego czytelnicy nie mogą odgadnąć.
Pascal Thivent

@Pascal w wersji 3.2.7.ga jest najnowszą wersją, jaką znalazłem w Maven. GroupId = org.hibernate i artifactId = hibernate. Zastanawiam się, czy Maven może dostarczyć najnowszą wersję, czy wystarczy skopiować słoik i zignorować maven.
TraderJoeChicago

@Sergio Dzieje się tak dlatego, że używasz starego monolitycznego jar ( hibernate), a nie hibernate-corektóry ma nowsze wersje. W przypadku ostatecznych wersji (3.5.x) są one dostępne w repozytorium JBoss Nexus .
Pascal Thivent

1
@ Pascal Thanks! Jednym dużym problemem jest to, że muszę przepuścić połączenie, więc jeśli Hibernate nie będzie w stanie zapewnić mi swojego połączenia, będzie źle. Będę musiał uzyskać to połączenie w inny sposób. Myślę, że ktokolwiek wpadł na pomysł rezygnacji z metody połączenia, powinien pomyśleć jeszcze raz.
TraderJoeChicago,

12

Spróbuj tego

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

W rzeczywistości getSession zwraca typ interfejsu sesji, powinieneś zobaczyć, jaka jest oryginalna klasa dla sesji, wpisz rzut do oryginalnej klasy, a następnie uzyskaj połączenie.

POWODZENIA!


1
❤️ uuuuu, więc to frustrujące - próba skonfigurowania mojej aplikacji do ustawienia połączeń tylko do odczytu w celu dystrybucji między replikami do odczytu. Dzięki.
Sam Berry

1
Dlaczego to nie ma więcej głosów za? Czy jest jakiś powód, dla którego nie powinno się tego robić? U mnie działa idealnie.

@tilper SessionImplznajduje się w wewnętrznym pakiecie Hibernate (więc nie jest przeznaczony do użycia), a także jest zależny od rzeczywistej implementacji. Nie możesz też łatwo kpić z sesji w swoich testach, kiedy ją przesyłasz.
Vic

9

Jest jeszcze jedna opcja, w której wciąż jest zaangażowanych wiele rzutów, ale przynajmniej nie wymaga ona refleksji, co pozwoli ci z powrotem sprawdzić czas kompilacji:

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

Możesz oczywiście uczynić to jeszcze „ładniejszym” kilkoma instanceofsprawdzeniami, ale powyższa wersja działa dla mnie.


9

Oto sposób na zrobienie tego w Hibernate 4.3 i nie jest on przestarzały:

  Session session = entityManager.unwrap(Session.class);
  SessionImplementor sessionImplementor = (SessionImplementor) session;
  Connection conn = sessionImplementor.getJdbcConnectionAccess().obtainConnection();

1
Czy konwersja sessionna format jest bezpieczna SessionImplementor?
macemers

@DerekY, wiem, że to jest stare, ale teraz sobie z tym radzę. I TAK, jest. Wszystkie implementacje Session są również w jakiś sposób SessionImplementor.
Reginaldo Santos

9

To jest to, czego używam i działa dla mnie. Przerzuć obiekt Session do SessionImpl i łatwo pobierz obiekt połączenia:

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

gdzie sessionjest nazwa obiektu sesji Hibernate.


8

connection()został właśnie wycofany w interfejsie. Nadal jest dostępny na SessionImpl. Możesz zrobić to, co robi Spring i po prostu to nazwać.

Oto kod z 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);
        }
    }

15
To jest rodzaj rzeczy, które robi niesamowita Hibernate. Niewiele frameworków jest tak złych jak Hibernate.
chrisapotek

8

Znalazłem ten artykuł

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

Pomogło mi.


6

Przy Hibernate> = 5,0 można uzyskać taki Connectionefekt:

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

3

W przypadku hibenate 4.3 spróbuj tego:

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

Spróbuj tego:

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

Oto metoda Java 8, która zwraca wartość Connectionużywaną przez program, EntityManagernie robiąc jeszcze nic z tym:

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();
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.