Comment faire pour réinitialiser le Pool de connexions JDBC

J'ai un problème lorsque je reçois tomcat exceptions après j'ai réinitialiser ma base de données MySQL à la demande de l'utilisateur via un tomcat web app. J'ai essayé de casser cette place dans l'installation, problème, et mon analyse jusqu'ici pour aider toute personne essayant de lire ceci.

Installation

La réinitialisation se compose essentiellement d'appeler un script bash à partir du code java:

  • Enlever le root de mysql mot de passe utilisateur
  • Chargement dans une ancienne version de la base de données
  • De l'exécution de certains scripts sur elle
  • La restauration de tous les mots de passe

Il est initié par l'utilisateur procédure pour restaurer habituellement la base de données à un état précédent, mais il est également utilisé pour l'importation d'une base de données à partir d'un autre système. Une fois que tout est terminé, l'utilisateur tente d'accéder à une autre partie de l'application web (c'est à dire avec la même session sans déconnexion/reconnexion) qui effectue un DB de requête pour obtenir certaines données.

Problème

Une fois la base de données est interrogée par l'application tomcat, il y a une exception:

Dec 29, 2014 3:49:50 PM ERROR BasicSecurityRealm:216 - 
ERROR: ----- SQLException -----

Dec 29, 2014 3:49:50 PM  INFO BasicSecurityRealm:218 - Exceptioncom.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet successfully received from the server was 234,810 milliseconds ago.  The last packet sent successfully to the server was 12 milliseconds ago.
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
...
Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
    at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:2540)
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:2990)

Même si l'utilisateur se déconnecte et à l'arrière, je vais voir cette exception. Si j'actualise la page, quatre fois, le chargement de la page un peu plus à chaque fois avec quelques exceptions (toutes les variantes de la ci - CommunicationsException causée par "EOFException: ne Peut pas lire la réponse du serveur"). La dernière fois, tout semble fonctionner normalement.

La seule chose que je peux faire pour éviter ces exceptions est de redémarrer tomcat. Je tiens à éviter, car cela signifie que l'utilisateur qui est connecté en vont perdre leur session et attendre pour tomcat pour redémarrer avant de pouvoir se connecter de nouveau. En les forçant à se déconnecter/retour peut-être un compromis acceptable, mais qui ne résout pas le problème de toute façon.

Analyse

De ce que je peux dire, je pense que le problème a à voir avec le pool de connexions JDBC. Je suis en utilisant JNDI sources de données pour accéder à ma base de données comme suit:

server.xml:

  <GlobalNamingResources>
    <Resource name="jdbc/mydb"
              auth="Container"
              type="javax.sql.DataSource"
              maxActive="30" maxIdle="30" maxWait="2147483647"
              username="x" password="x"
              driverClassName="com.mysql.jdbc.Driver"
              url="jdbc:mysql://localhost:3306/mydb?autoReconnect=true"/>

web.xml:

<!-- Data source definitions -->
<resource-ref>
    <res-ref-name>jdbc/mydb</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

Java:

    //Get connection to specified database
    Context initCtx = new InitialContext();
    Context envCtx = (Context) initCtx.lookup("java:comp/env");
    DataSource ds = (DataSource) envCtx.lookup("jdbc/mydb");
    con = ds.getConnection();
    stmt = con.createStatement();
    rs = stmt.executeQuery("...");

Je crois que le pool de connexion contient les connexions qui sont obsolètes/morts. Chaque fois que j'ai une connexion avec ds.getConnection, puis il est arriver un de ces connexions. Les tentatives d'utilisation il échoue la première fois, et la connexion est réinitialisée (notez que j'utilise autoReconnect=true, de sorte que la deuxième fois doit (et) de travail). Cependant, la piscine contient beaucoup (dans mon cas, empiriquement 4 ou 5), rassis, les connexions, donc ça prend du temps avant qu'ils soient tous correctement réinitialisé. Une fois qu'une connexion est réinitialisée, tout se comporte correctement.

Solutions?

Depuis que j'utilise autoReconnect=true j'ai pu re-structure de mon code de façon à ce que si j'obtiens une exception lorsque je tente une requête, je peux réessayer une fois la requête. S'il échoue à nouveau, alors je sais qu'il y a vraiment un problème. Si elle passe, la connexion a été rétablie avec succès.

Le problème, c'est qu'il y a des questions PARTOUT dans le code. Re-factoring eux tous prendrait beaucoup de temps et d'essais, ce que je ferai si nécessaire, mais éviter. Aussi, si la requête échoue pour d'autres raisons, il serait tenté deux fois avant d'être signalés. Pendant de longues requêtes, cela pourrait avoir une grande expérience de l'utilisateur retard, mais seulement dans des conditions d'erreur.

Une autre solution serait d'obliger une réinitialisation/reconnexion de toutes les connexions dans le pool de connexion. J'ai pu le faire par programmation (c'est à dire à partir de mon code java lors de l'invocation du script bash complète) ou dans le script bash (par exemple avec un certain type d'utilitaire de ligne de commande). Le problème est, je ne sais pas comment faire, ou si c'est encore possible.

J'ai trouvé de la documentation sur les Intercepteurs, mais je ne suis pas sûr si cela serait pour la réinitialisation de la connexion. Je vais continuer à étudier.

Merci à tous pour votre temps et de votre aide!

Solution: ne pas supprimer les informations d'identification de l'utilisateur que vous avez configuré dans votre base de données du pool de connexions. En fait, vous ne devriez pas mess avec mysql données de l'utilisateur dans le but de modifier l'état de votre base de données. Vous ne devez modifier le schéma que vous travaillez avec.
j'avais pensé à ça, mais c'est une longue histoire courte, cela pourrait ne pas être une option puis souffrir en silence u_u. Blagues à part, vous ne pouvez pas reset une connexion à la base de la piscine. Éviter de le faire, ou à exécuter votre script avec un utilisateur qui a assez de puissance pour le faire. Vous pouvez créer un autre utilisateur, ou la fermeture de vos applications et les lancer de nouveau et d'établir des politiques pour cela.
Je suppose que toute votre approche vous donne ce problème et que vous essayez d'utiliser un sale tour à résoudre votre conception. Ma recommandation est: oui, envoyer ce mot de passe en argument au script et oublient même de jouer avec mysql identification de l'utilisateur tous. C'est ça le problème, peu importe comment vous le décrire, c', et vous devriez éviter cette étape et utiliser nettoyeur de dessins.
Si vous comprenez comment un pool de connexions de base de données fonctionne, alors vous ne devriez pas être surpris de ce résultat, si vous redémarrez votre moteur de base de données. La solution, encore une fois, n'est pas de réinitialiser la connexion de la piscine, mais l'établissement de politiques pour redémarrer votre moteur de base de données. Si vous allez à redémarrer votre moteur, redémarrez votre apps.
Oui............

OriginalL'auteur Trenin | 2014-12-29