Uzyskiwanie połączenia z bazą danych w czystej konfiguracji JPA
Mamy aplikację JPA (używającą hibernate) i musimy przekazać wywołanie do starszego narzędzia do raportowania, które wymaga połączenia z bazą danych JDBC jako parametru. Czy istnieje prosty sposób, aby uzyskać dostęp do połączenia JDBC Hibernate ma skonfigurowany?
12 answers
Gdzie chcesz uzyskać to połączenie jest niejasne. Jedną z możliwości jest pobranie go z bazowego Hibernate Session
używanego przez EntityManager
. Z JPA 1.0 będziesz musiał zrobić coś takiego:
Session session = (Session)em.getDelegate();
Connection conn = session.connection();
Zauważ, że getDelegate()
nie jest przenośny, wynik tej metody jest specyficzny dla implementacji: powyższy kod działa w JBoss, dla GlassFish musiałbyś go dostosować-spójrz na bądź ostrożny podczas używania Entitymanagera.getDelegate () .
W JPA 2.0, rzeczy są nieco lepsze i można zrobić następujące:
Connection conn = em.unwrap(Session.class).connection();
Jeśli uruchamiasz się wewnątrz kontenera, możesz również przeprowadzić wyszukiwanie na skonfigurowanym DataSource
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-16 20:50:42
Zgodnie z hibernate
docs TUTAJ ,
Connection connection ()
Deprecated . (planowane do usunięcia w 4.x). Wymiana zależy od potrzeby; do robienia bezpośrednich rzeczy JDBC używać doWork(org.hibernacja.jdbc.Pracy)...
Zamiast tego użyj interfejsu Hibernate Work API:
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
}
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-13 10:57:50
Jeśli używasz JAVA EE 5.0, najlepszym sposobem na to jest użycie adnotacji @ Resource, aby wstrzyknąć datasource do atrybutu klasy (na przykład EJB) do przechowywania zasobu datasource (na przykład Oracle datasource) dla starszego narzędzia do raportowania, w ten sposób:
@Resource(mappedName="jdbc:/OracleDefaultDS") DataSource datasource;
Później możesz uzyskać połączenie i przekazać je do starszego narzędzia raportującego w ten sposób:
Connection conn = dataSource.getConnection();
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-28 18:55:31
Jeśli używasz EclipseLink: Powinieneś być w transakcji JPA, aby uzyskać dostęp do połączenia
entityManager.getTransaction().begin();
java.sql.Connection connection = entityManager.unwrap(java.sql.Connection.class);
...
entityManager.getTransaction().commit();
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-10 04:12:24
Ponieważ kod sugerowany przez @ Pascal jest przestarzały, jak wspomniał @ Jacob, znalazłem inny sposób , który działa dla mnie.
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();
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-06 09:54:37
Słowo pure nie pasuje do słowa hibernate .
Dzielę się swoimi kodami.
Powiedzmy, że możemy zdefiniować metodę użycia Connection
wywodzącą się z EntityManager
.
static <R> applyConnection(final EntityManager manager,
final Function<Connection, R> function) {
if (manager == null) {
throw new NullPointerException("manager is null");
}
if (function == null) {
throw new NullPointerException("function is null");
}
// we gonna fill here up
throw new RuntimeException("failed to work with a connection");
}
EclipseLink
Jest to dość proste, jak opisano powyżej link.
- zauważ, że
EntityManager
musi być połączone zTransaction
lub metodaunwrap
zwrócinull
. (Niezbyt dobry ruch.)
Nie jestem pewien, czy powinienem zamknąć połączenie.
// --------------------------------------------------------- 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
Powinno być w zasadzie zrobione za pomocą następujących kodów.
// 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);
}
});
Cóż, my (przynajmniej ja) możemy nie chcieć żadnych zależności specyficznych dla dostawcy. Proxy przychodzi na ratunek.
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
Nie jestem pewien, czy OpenJPA już obsługuje sposób używając unwrap(Connection.class)
, ale można to zrobić w sposób opisany w jednym z powyższych linków.
Nie jest jasne, jaka jest odpowiedzialność za zamknięcie połączenia. Dokument (jeden z powyższych linków) wydaje się wyraźnie mówić, ale nie jestem dobry w języku angielskim.
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");
}
Załącznik
static <U, R> R applyConnection(
final EntityManager manager,
final BiFunction<Connection, U, R> function, final U u) {
if (manager == null) {
throw new NullPointerException("manager is null");
}
if (function == null) {
throw new NullPointerException("function is null");
}
return applyConnection(manager, t -> function.apply(t, u));
}
static void acceptConnection(
final EntityManager manager, final Consumer<Connection> consumer) {
if (manager == null) {
throw new NullPointerException("manager is null");
}
if (consumer == null) {
throw new NullPointerException("consumer is null");
}
applyConnection(
manager,
t -> {
consumer.accept(t);
return null;
}
);
}
static <U> void acceptConnection(
final EntityManager manager,
final BiConsumer<Connection, U> consumer, final U u) {
if (manager == null) {
throw new NullPointerException("manager is null");
}
if (consumer == null) {
throw new NullPointerException("consumer is null");
}
acceptConnection(manager, t -> consumer.accept(t, u));
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-27 08:15:24
Z Hibernate 4 / 5:
Asynchroniczny:
Session session = entityManager.unwrap(Session.class);
session.doWork(connection -> doSomeStuffWith(connection));
Syncronous:
Session session = entityManager.unwrap(Session.class);
Connection cnn = session.doReturningWork(c -> c);
Lub pojedyncze:
Connection cnn = em.unwrap(Session.class).doReturningWork(c -> c);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-31 22:06:34
Hibernate używa wewnętrznie ConnectionProvider do uzyskania połączeń. Z Hibernate javadoc:
Interfejs ConnectionProvider nie jest przeznaczony do kontaktu z aplikacją. Zamiast tego jest używany wewnętrznie przez Hibernate do uzyskiwania połączeń.
Bardziej eleganckim sposobem rozwiązania tego problemu byłoby samodzielne utworzenie puli połączeń bazodanowych i ręczne Połączenie z hibernate i z tego narzędzia.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-16 13:55:50
Wpadłem dziś na ten problem i to była moja sztuczka, która zadziałała na mnie:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("DAOMANAGER");
EntityManagerem = emf.createEntityManager();
org.hibernate.Session session = ((EntityManagerImpl) em).getSession();
java.sql.Connection connectionObj = session.connection();
Chociaż nie jest to najlepszy sposób, ale wykonuje swoją pracę.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-17 14:43:21
Używam starej wersji Hibernate (3.3.0) z najnowszą wersją OpenEJB (4.6.0). Moje rozwiązanie to:
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);
}
Potem miałem błąd:
Commit can not be set while enrolled in a transaction
Ponieważ powyższy kod znajdował się wewnątrz kontrolera EJB (nie możesz commit
wewnątrz transakcji). Opisałem metodę @TransactionAttribute(value = TransactionAttributeType.NOT_SUPPORTED)
i problem zniknął.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-02 18:17:04
Oto fragment kodu, który działa z Hibernate 4 na podstawie odpowiedzi Dominika
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;
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-27 20:06:09
Poniżej znajduje się kod, który działał dla mnie. Używamy jpa 1.0, implementacji Apache openjpa.
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;
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-23 21:02:37