Question

J'ai une application web qui utilise JNDI recherches pour obtenir une connexion à la base de données.

La connexion fonctionne très bien et renvoie la requête, pas de problèmes.La question nous que la connexion ne se ferme pas correctement et est coincé dans le mode "veille" (selon l'administrateur mysql).Cela signifie qu'ils deviennent inutilisables nad puis je n'ai plus de connexions.

Quelqu'un peut-il me donner quelques indications sur ce que je peux faire pour rendre la connexion de retour à la piscine avec succès.

public class DatabaseBean {

private static final Logger logger = Logger.getLogger(DatabaseBean.class);

private Connection conn;
private PreparedStatement prepStmt;

/**
 * Zero argument constructor
 * Setup generic databse connection in here to avoid redundancy
 * The connection details are in /META-INF/context.xml
 */
public DatabaseBean() {
    try {
        InitialContext initContext = new InitialContext();
        DataSource ds = (DataSource) initContext.lookup("java:/comp/env/jdbc/mysite");
        conn = ds.getConnection();
    }
    catch (SQLException SQLEx) {
        logger.fatal("There was a problem with the database connection.");
        logger.fatal(SQLEx);
        logger.fatal(SQLEx.getCause());
    }
    catch (NamingException nameEx) {
        logger.fatal("There was a naming exception");
        logger.fatal(nameEx);
        logger.fatal(nameEx.getCause());
    }
}

/**
 * Execute a query. Do not use for statements (update delete insert etc).
 *
 * @return A ResultSet of the execute query. A set of size zero if no results were returned. It is never null.
 * @see #executeUpdate() for running update, insert delete etc.
 */

public ResultSet executeQuery() {
    ResultSet result = null;
    try {
        result = prepStmt.executeQuery();
        logger.debug(prepStmt.toString());
    }
    catch (SQLException SQLEx) {
        logger.fatal("There was an error running a query");
        logger.fatal(SQLEx);
    }
    return result;
}

SNIP

public void close() {
    try {
        prepStmt.close();
        prepStmt = null;

        conn.close();
        conn = null;
    } catch (SQLException SQLEx) {
        logger.warn("There was an error closing the database connection.");
    }
}
}

C'est à l'intérieur d'un javabean qui utilise la connexion de base de données.

public LinkedList<ImportantNoticeBean> getImportantNotices() {

    DatabaseBean noticesDBBean = new DatabaseBean();
    LinkedList<ImportantNoticeBean> listOfNotices = new LinkedList<ImportantNoticeBean>();

    try {
        PreparedStatement preStmt = noticesDBBean.getConn().prepareStatement("SELECT pseudonym, message, date_to, date_from " +
                "FROM importantnotices, users " +
                "WHERE importantnotices.username = users.username " +
                "AND NOW() >= date_from AND NOW() <= date_to;");

        noticesDBBean.setPrepStmt(preStmt);
        ResultSet result = noticesDBBean.executeQuery();

        while (result.next()) {
            ImportantNoticeBean noticeBean = new ImportantNoticeBean();

            noticeBean.setAuthor(result.getString("pseudonym"));
            noticeBean.setMessage(result.getString("message"));
            noticeBean.setDateTo(result.getDate("date_to"));
            noticeBean.setDateFrom(result.getDate("date_from"));

            listOfNotices.add(noticeBean);
        }

        result.close();

    } catch (SQLException SQLEx) {
        logger.error("There was an error in ImportantNoticesBean.getImportantNotices()");
        logger.error(SQLEx);
    } finally {
        noticesDBBean.close();
    }
    return listOfNotices;
}

<Context reloadable="true">

    <Resource name="jdbc/mysite"
              auth="Container"
              type="javax.sql.DataSource"
              username="user"
              password="password"
              driverClassName="com.mysql.jdbc.Driver"
              url="jdbc:mysql://localhost:3306/mysite"
              maxActive="10"
              maxIdle="5"
              maxWait="6000"
              removeAbandoned="true"
              logAbandoned="false"
              removeAbandonedTimeout="20"
            />
</Context>
Était-ce utile?

La solution 4

La question nous que la connexion ne se ferme pas correctement et est coincé dans le mode "veille"

Ce n'était en fait qu'à moitié raison.

Le problème que j'ai rencontré était en fait que chaque application a été la définition d'une nouvelle connexion à la base de données serveur.Donc, chaque fois que j'ai fermé toutes les connexions App, serait de faire un tas de nouvelles connexions selon que c'est la WEB.xml le fichier de configuration et courir joyeusement.L'application B ferait la même chose.Le problème, c'est qu'ils sont piscines indépendants qui essaye d'attraper au serveur limite définie.C'est une sorte de condition de course, je suppose.Alors, quand Une Application a fini avec les connexions qu'il s'assoit en attendant de les utiliser de nouveau jusqu'à ce que le délai d'attente a passé tandis que l'Application B qui a besoin de la connexion est maintenant refusé les ressources, même si l'Application A a fini avec la et devrait être de retour dans la piscine.Une fois le délai écoulé, la connexion est libéré et B (ou C, etc), vous pouvez obtenir à nouveau.

par exemplesi la limite est de 10 (mySQL profil de limite) et chaque application a été configuré pour utiliser un maximum de 10 la il y aura 20 tentatives de connexions.C'est évidemment une mauvaise situation.

La solution est de RTFM et de mettre le les détails de la connexion à la bonne place.Cela ne faire partagé poster une douleur, mais il ya des façons de contourner cela (comme des liens vers d'autres fichiers xml à partir du contexte).

Juste pour être explicite:J'ai mis les détails de connexion dans le WEB.xml pour chaque application, et le eu un combat à ce sujet.

Autres conseils

Vous semblez être la fermeture de la connexion correctement sauf pour le cas où prepStmt.close() lève une exception SQLException, je ne peux pas trouver un lien de fuite.

Ce pool de mise en œuvre utilisez-vous?Lorsque vous fermez une connexion, la piscine n'a pas besoin de fermer le sous-jacent de connexion MySQL immédiatement - après tout, c'est le point de connexion de la piscine!Donc, à partir de MySQL côté, les connexions regarder en vie, même si votre application n'utilise pas toutes;ils pourraient simplement être tenu par le TC pool de connexion.

Vous pouvez essayer avec les paramètres du pool de connexion.Demandez à réduire la piscine lorsque le système est inactif.Ou, demandez-la à actualiser toutes les connexions périodiquement.Ou, avoir une stricte limite supérieure sur le nombre de connexions simultanées qu'il obtient à partir de MySQL etc.

Une façon de vérifier si votre code a une connexion de fuite est à la force de la ds.getConnection() à toujours ouvrir une nouvelle connexion physique et conn.close() pour libérer la connexion (si votre pool de connexion a des paramètres pour ces).Ensuite, si vous regardez les connexions MySQL côté, vous pourriez être en mesure de comprendre si le code a vraiment une connexion de fuite ou pas.

C'est une question semblable - Paramètres du Pool de connexions pour Tomcat

C'est ma réponse à cette question et il a résolu le problème pour les autres gars.Il peut vous aider trop.

La Documentation De Tomcat

DBCP utilise le Jakarta-Commons Connexion à la Base de la Piscine.Il s'appuie sur le nombre de Jakarta-Commons composants:

* Jakarta-Commons DBCP
* Jakarta-Commons Collections
* Jakarta-Commons Pool

Je suis en utilisant la même connexion de mise en commun des trucs et je suis à la définition de ces propriétés afin de prévenir la même chose, c'est juste pas configuré par le biais de tomcat.Mais si la première chose ne fonctionne pas, essayez ces.

testWhileIdle=true
timeBetweenEvictionRunsMillis=300000

Ok je ce pourrait être triés.J'ai changé la config de la base de données de ressources à la suivante:

*SNIP*
maxActive="10"
maxIdle="5"
maxWait="7000"
removeAbandoned="true"
logAbandoned="false"
removeAbandonedTimeout="3"
*SNIP*

Cela fonctionne assez bien pour l'instant.Ce qui se passe, autant que je sache, c'est que une fois que j'arrive à la dix connexions puis Tomcat est la vérification de abandonnés les connexions (temps d'inactivité > 3).Il le fait dans un lot de travail chaque fois que max connexions est atteint.Le potentiel problème avec ceci est que si j'ai besoin de plus de 10 requêtes exécutées en même temps (pas unique pour moi).La chose importante est que removeAbandonedTimeout est à moins de maxWait.

Est-ce en quoi devrait-il se passer?c'est à dire Est-ce ainsi que la piscine doit fonctionner?Si c'est paraît-il, au moins pour moi, que vous attendez jusqu'à ce que quelque chose (la connexion) est cassé avant de réparer plutôt que de ne pas le laisser "pause" dans la première place.Peut-être que je ne suis toujours pas à l'obtenir.

Une chose que @binil manqué, vous ne ferme pas le jeu de résultats dans le cas d'une exception.Selon le pilote de la mise en œuvre peut entraîner la connexion à rester ouvert.Déplacez le résultat.close() appel pour le bloc finally.

Je suis en utilisant la même configuration que vous.Si la connexion à mysql administrator(windows) montre qu'il est en mode veille, seul moyen qui est mis en commun, mais ne l'utilisez pas.J'ai vérifié cette exécution d'un programme de test du programme avec plusieurs threads aléatoires de requêtes pour Mysql.si ça aide, voici ma configuration:

        defaultAutoCommit="false"
        defaultTransactionIsolation="REPEATABLE_READ"
        auth="Container"
        type="javax.sql.DataSource"
        logAbandoned="true" 
          removeAbandoned="true"
        removeAbandonedTimeout="300" 
        maxActive="-1"
        initialSize="15"
        maxIdle="10"
        maxWait="10000" 
        username="youruser"
        password="youruserpassword"
        driverClassName="com.mysql.jdbc.Driver"
        url="jdbc:mysql://yourhost/yourdatabase"/>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top