JPA Hibernate Appel Postgres Fonction de Retour Void MappingException:
J'ai un problème lorsque je reçois un: org.mise en veille prolongée.MappingException: Aucun Dialecte de cartographie pour JDBC de type: 1111 lorsque vous essayez d'appeler une postgres de la fonction en utilisant JPA créer des indigènes de la requête.
J'ai créé un EJB minuterie de démarrage singleton pour exécuter une Postgres fonction toutes les 6 heures. La fonction de type void et vérifie les enregistrements expirés, les supprime, et les mises à jour de certains statuts. Il ne prend pas d'argument et renvoie void.
-
La postgres fonction fonctionne parfaitement si je l'appelle à l'aide PgAdmin outil de requête (fonction select();) et renvoie void.
-
Pour le déploiement de l'application sur Glassfish 3.1.1 j'obtiens une exception et d'une incapacité à déployer.
C'est l' (raccourcie) de la trace de pile:
WARNING: A system exception occurred during an invocation on EJB UserQueryBean method public void com.mysoftwareco.entity.utility.UserQueryBean.runRequestCleanup()
javax.ejb.TransactionRolledbackLocalException: Exception thrown from bean
...STACK TRACE BLAH BLAH BLAH ...
Caused by: javax.persistence.PersistenceException: org.hibernate.MappingException: No Dialect mapping for JDBC type: 1111
Voici le code:
D'abord l'APP étoffe:
public void runRequestCleanup() {
String queryString = "SELECT a_function_that_hibernate_chokes_on()";
Query query = em.createNativeQuery(queryString);
Object result = query.getSingleResult();
}
C'est le singleton en l'appelant:
@Startup
@Singleton
public class RequestCleanupTimer {
@Resource
TimerService timerService;
@EJB
UserQueryBean queryBean;
@PostConstruct
@Schedule(hour = "*/6")
void runCleanupTimer() {
queryBean.runRequestCleanup();
}
}
Et la fonction:
CREATE OR REPLACE FUNCTION a_function_that_hibernate_chokes_on()
RETURNS void AS
$BODY$
DECLARE
var_field_id myTable.field_id%TYPE;
BEGIN
FOR var_field_id IN
select field_id from myTable
where status = 'some status'
and disposition = 'some disposition'
and valid_through < now()
LOOP
BEGIN
-- Do Stuff
END;
END LOOP;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
Vous devez vous connecter pour publier un commentaire.
Cela pourrait être un hack, mais il a travaillé pour moi et c'est assez simple. Il suffit de changer la requête:
Maintenant, il renvoie un bon nombre entier et hibernate est heureux.
J'ai eu assez de déconner avec JPA essayer de l'obtenir pour exécuter une procédure stockée.
J'ai fini à l'aide de JDBC avec une déclaration préparée. Je l'ai fait dans les 15 minutes après avoir passé plusieurs vaines heures à essayer de s'adapter à une cheville carrée dans un trou rond. J'ai appelé le même datasource jndi mon unité de persistance utilise pour obtenir une connexion, créé une instruction préparée et fermé lorsque vous avez terminé.
Donc, si vous avez besoin d'exécuter une procédure stockée (ou Postgres fonction) à partir d'une (maintenant la plupart du temps) JPA application, voici ce qui a fonctionné pour moi:
Il semble y avoir un horrible surveillance sortir par la simple capacité à exécuter une fonction ou une procédure stockée sur le serveur de JPA; en particulier celui qui ne retourne rien, sauf nullité ou le nombre de lignes affectées. Et si c'était délibéré ... sans commentaire.
Edit: ajout de la fermeture de la connexion.
Il semble que le problème se produit lorsque la postgres procédure stockée renvoie void. Essayez de changer le type de retour de rendre une certaine valeur factice, peut-être une chaîne de caractères. Cela a fonctionné dans mon cas.
Cela a été posté il y a quelques temps, mais j'ai eu le même problème. Comme indiqué, Hibernate semble allergique à vide et va essayer de vous enfermer en utilisant le type de retour à chaque fois. De mon point de vue, c'est une bonne pratique que vous devriez toujours avoir un retour, au moins, de préciser s'il a réussi: le fait de lancer une exception est souvent abusif.
Encore, Hibernate offre un moyen de contourner ses limites: org.mise en veille prolongée.jdbc.Travail
Vous pouvez facilement reproduire ce qui était nécessaire, dans une petite classe:
Maintenant, vous pouvez appeler quand vous le souhaitez en utilisant
VoidProcedureWork.execute(hibernateSession, sqlQuery);
Vous remarquerez deux choses à propos de cette classe:
1) je ne ferme PAS la Connexion. Je le laisse parce que je ne sais pas qui a ouvert la Connexion, comment et pourquoi. Est la même connexion utilisé dans une transaction? Si je le ferme ant quelqu'un l'utilise après, il va tomber? Etc. Je n'ai pas de code Hibernate et de ne pas utiliser de connexion.open(). Par conséquent, je ne la fermez pas et assumer quelque soit ouvert, il se ferme aussi.
2) Il est plus programmation procédurale de la POO. Je sais, mais je suis paresseux: il est plus facile (et plus claire de l'omi) à utiliser VoidProcedureWork.execute(session, sql) que la nouvelle VoidProcedureWork(sql).execute(session). Ou même pire: reproduire le code d'exécuter à chaque fois que je veux utiliser cette petite astuce (session.doWork(nouveau VoidProcedureWork(sql)) à l'exception du traitement).
Pour les futurs visiteurs de cette question, un casting aurait fonctionné aussi. posté le ce fil ainsi
Mec! C'est aussi facile que de citer le nom de la fonction. Comme: