Obtenir une connexion à la firebase database dans une configuration JPA pure

Nous avons une application JPA (utilisant la mise en veille prolongée) et nous devons passer un appel à un outil de génération de rapports hérité nécessitant une connexion à la firebase database JDBC en tant que paramètre. Existe-t-il un moyen simple d’accéder à la connexion JDBC?

Où vous voulez obtenir cette connexion n’est pas claire. Une possibilité serait de l’obtenir depuis la Session Hibernate sous-jacente utilisée par EntityManager . Avec JPA 1.0, vous devrez faire quelque chose comme ceci:

 Session session = (Session)em.getDelegate(); Connection conn = session.connection(); 

Notez que getDelegate() n’est pas portable, le résultat de cette méthode est spécifique à l’implémentation: le code ci-dessus fonctionne dans JBoss, pour GlassFish vous devrez l’adapter – jetez un oeil à Attention avec EntityManager.getDelegate () .

Dans JPA 2.0, les choses vont un peu mieux et vous pouvez faire ce qui suit:

 Connection conn = em.unwrap(Session.class).connection(); 

Si vous utilisez un conteneur, vous pouvez également effectuer une recherche sur le DataSource configuré.

Selon les documents d’ hibernate ici ,

Connexion de connexion ()

Déconseillé . (prévu pour l’enlèvement dans 4.x). Le remplacement dépend des besoins; pour faire des trucs JDBC directs, utilisez doWork (org.hibernate.jdbc.Work) …

Utilisez plutôt l’API Hibernate Work:

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

Si vous utilisez JAVA EE 5.0, la meilleure façon de procéder consiste à utiliser l’annotation @Resource pour injecter la source de données dans un atsortingbut d’une classe (par exemple, un EJB) pour contenir la ressource de source de données (par exemple une source de données Oracle) pour l’outil de reporting hérité, de cette manière:

 @Resource(mappedName="jdbc:/OracleDefaultDS") DataSource datasource; 

Plus tard, vous pouvez obtenir la connexion et la transmettre à l’outil de génération de rapports hérité de cette manière:

 Connection conn = dataSource.getConnection(); 

si vous utilisez EclipseLink: vous devez être dans une transaction JPA pour accéder à la connexion

 entityManager.getTransaction().begin(); java.sql.Connection connection = entityManager.unwrap(java.sql.Connection.class); ... entityManager.getTransaction().commit(); 

Puisque le code suggéré par @Pascal est déconseillé, comme mentionné par @Jacob, j’ai trouvé cela comme une autre façon de travailler pour moi.

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

Avec Hibernate 4/5 :

asyncroneux:

 Session session = entityManager.unwrap(Session.class); session.doWork(connection -> doSomeStuffWith(connection)); 

syncroneux:

 Session session = entityManager.unwrap(Session.class); Connection cnn = session.doReturningWork(c -> c); 

ou individuel:

 Connection cnn = em.unwrap(Session.class).doReturningWork(c -> c); 

Hibernate utilise un ConnectionProvider en interne pour obtenir des connexions. De l’hibernate javadoc:

L’interface ConnectionProvider n’est pas destinée à être exposée à l’application. Au lieu de cela, il est utilisé en interne par Hibernate pour obtenir des connexions.

La manière la plus élégante de résoudre ce problème serait de créer vous-même un pool de connexions à une firebase database et de créer des connexions à la mise en veille prolongée et à votre ancien outil.

Le mot pur ne correspond pas au mot hibernation .

Je partage mes codes.

Disons que nous pouvons définir une méthode pour utiliser Connection dérivée d’un EntityManager .

 static  applyConnection(final EntityManager manager, final Function 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

  • Obtenir une connexion JDBC à partir d’un EntityManager

C’est un peu simple comme décrit dans le lien ci-dessus.

  • Notez que EntityManager doit être associé à une Transaction ou que la méthode unwrap renvoie null . (Pas un bon coup du tout.)
  • Je ne suis pas sûr de la responsabilité de fermer la connexion.
 // --------------------------------------------------------- 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"); } 

Hiberner

Cela devrait se faire, en gros, avec les codes suivants.

 // using vendor specific APIs final Session session = (Session) manager.unwrap(Session.class); //return session.doReturningWork(function::apply); return session.doReturningWork(new ReturningWork() { @Override public R execute(final Connection connection) { return function.apply(connection); } }); 

Eh bien, nous (au moins moi) pourrions ne pas vouloir de dépendances spécifiques à un fournisseur. Proxy vient en sauvetage.

 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

  • Accès à l’exécution à DataSource
  • OPENJPA-1803 Développer EntityManager en connexion

Je ne suis pas sûr qu’OpenJPA serve déjà un moyen d’utiliser unwrap(Connection.class) mais peut être fait de la manière décrite dans l’un des liens ci-dessus.

La responsabilité de fermer la connexion n’est pas claire. Le document (l’un des liens ci-dessus) semble dire clairement mais je ne suis pas bon en anglais.

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

ANNEXE

 static  R applyConnection( final EntityManager manager, final BiFunction 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 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  void acceptConnection( final EntityManager manager, final BiConsumer 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)); } 

J’ai rencontré ce problème aujourd’hui et c’était le tour que j’ai fait, qui a fonctionné pour moi:

  EntityManagerFactory emf = Persistence.createEntityManagerFactory("DAOMANAGER"); EntityManagerem = emf.createEntityManager(); org.hibernate.Session session = ((EntityManagerImpl) em).getSession(); java.sql.Connection connectionObj = session.connection(); 

Bien que pas le meilleur moyen, mais fait le travail.

J’utilise une ancienne version d’Hibernate (3.3.0) avec une nouvelle version d’OpenEJB (4.6.0). Ma solution était:

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

J’ai eu une erreur après cela:

 Commit can not be set while enrolled in a transaction 

Parce que ce code ci-dessus se trouvait dans un contrôleur EJB (vous ne pouvez pas vous commit dans une transaction). J’ai annoté la méthode avec @TransactionAtsortingbute(value = TransactionAtsortingbuteType.NOT_SUPPORTED) et le problème a disparu.

Voici un extrait de code qui fonctionne avec Hibernate 4 en fonction de la réponse de Dominik

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

Voici le code qui a fonctionné pour moi. Nous utilisons l’implémentation jpa 1.0, 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; } }