m'aider à éviter d'attente de la connexion avec JPA, Hibernate & MySQL

Je suis en utilisant JPA (Hibernate en tant que fournisseur), Glassfish et MySQL. Tout fonctionne très bien en développement, mais quand j'ai déployer l'application sur un serveur de test et de le laisser fonctionner (en grande partie en veille) pour la nuit, je suis généralement accueillis avec cela le matin:

[#|2011-03-09T15:06:00.229+0000|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=23;_ThreadName=Thread-1;|ERROR [htt\
p-thread-pool-8080-(1)] (JDBCTransaction.java:91) - JDBC begin failed
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 41,936,868 milliseconds ago.  The last packet \
sent successfully to the server was 41,936,868 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expirin\
g and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connec\
tion property 'autoReconnect=true' to avoid this problem.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:532)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:409)
at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1118)
at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3321)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1940)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2113)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2562)
at com.mysql.jdbc.ConnectionImpl.setAutoCommit(ConnectionImpl.java:4956)
at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:87)
at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1473)
at org.hibernate.ejb.TransactionImpl.begin(TransactionImpl.java:60)

J'ai essayé à l'aide de la suite dans mon persistence.xml, mais il n'a pas aidé:

        <property name="hibernate.c3p0.min_size" value="5"/>
<property name="hibernate.c3p0.max_size" value="20"/>
<property name="hibernate.c3p0.idleTestPeriod" value="30"/>
<property name="hibernate.c3p0.timeout" value="0"/>
<property name="hibernate.c3p0.max_statements" value="0"/>

De sorte que la C3p0 de configuration; il est tout à fait possible que je me manque la partie réellement indique à hibernate "hé, utilisez c3p0".

Je suis sur le point d'essayer la suggestion qui est là, dans le message d'erreur: ajouter autoReconnect=true à mon URL JDBC, mais c'est vraiment de commencer à se sentir comme cargo culte de développement à ce point. J'aimerais avoir quelques conseils sur la bonne façon de répondre à cette question. C'est difficile à déboguer, parce que le cycle de test est effectivement "fonctionne toute la nuit, de voir ce qui se passe dans la matinée".

Je devrais probablement mentionner à quel point je suis en fait en utilisant des connexions dans mon application. J'ai un custom Filtre De Servlet qui intercepte toutes les requêtes. Il crée un EntityManager, il les stocke dans un ThreadLocal, et est fermé par le filtre dans un catch/finally bloc. Toutes mes entités obtenir une référence à la EntityManager de la ThreadLocal.

Il est tout à fait possible que mon filtre est en faute, mais comme elle ne semble se produire après des périodes d'inactivité, je soupçonne autre chose est erroné. J'ai l'intention d'aller à la Couture/Soudure quand j'ai une chance de reprendre mon souffle, mais pour l'instant je suis plutôt sur ce filtre.

Edit: voici le TL;DR solution:

  • utiliser votre conteneur du pool de connexion, si vous le pouvez (merci, @partenon)
  • assurez-vous que votre pool de connexion utilise connexion de validation (merci, @matt b)

Dans mon cas, j'ai dû aller dans Glassfish console, à la rubrique Ressources/JDBC/Pools de Connexion, Onglet Avancé, puis activez la Connexion de Validation:

m'aider à éviter d'attente de la connexion avec JPA, Hibernate & MySQL

C'était vraiment une étape cruciale. Vous aussi vous voulez probablement pour définir Validate At Most Once à quelque chose de raisonnable, de 100 secondes. Si vous êtes à l'aide de C3P0 ou similaire, assurez-vous de configurer idle_test_period et preferredTestQuery.

Tout ce que vous finissez par faire, il est important de tester vos modifications pour voir si ils ont l'effet désiré. Pour rendre le délai d'attente arriver plus vite dans MySQL, vous pouvez activer temporairement l' wait_timeout à quelque chose de faible, comme 30 secondes par l'édition my.cnf. Ce fut d'une grande aide au débogage de ce problème, car il m'a permis de tester en quelques secondes, plutôt qu'en heures.

OriginalL'auteur George Armhold | 2011-03-09