Frage

Ich habe eine webapp, die verwendet JNDI-lookups, um eine Verbindung zu der Datenbank.

Die Verbindung funktioniert gut und liefert die Abfrage keine Probleme.Das Problem uns, dass die Verbindung nicht richtig schließen und bleibt in der "Standby" - Modus (je nach mysql-administrator).Dies bedeutet, dass Sie unbrauchbar nad dann habe ich verbindungen.

Kann mir jemand ein paar Hinweise, was ich tun kann, um die Verbindung zurück an den pool erfolgreich.

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

Dies ist im inneren, der eine javabean verwendet die Datenbank-Verbindung.

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>
War es hilfreich?

Lösung 4

Das Problem uns, dass die Verbindung nicht richtig schließen und bleibt in der "Standby" - Modus

Dies war eigentlich nur halb richtig.

Das problem, das ich gestoßen bin, war eigentlich, dass jede app definieren Sie eine neue Verbindung zur Datenbank trennen.Also jedes mal, wenn ich geschlossen, alle verbindungen-App machen würde, eine Reihe von neuen verbindungen als pro Sie ist WEB.xml config-Datei, und führen Sie gerne.App B würde das gleiche tun.Das problem ist, dass Sie unabhängige pools die versuche, auf den server definierte Grenze.Es ist eine Art von race-Bedingung, die ich Schätze.Also, wenn Eine App beendet hat, mit den Anschlüssen sitzt Sie warten, um Sie erneut verwenden, bis das timeout verstrichen, während die App B, die die Verbindung muss nun verweigert die Ressourcen, auch wenn App beendet hat, mit der und sollte wieder in den pool.Sobald das Zeitlimit abgelaufen, wird die Verbindung freigegeben und B (oder C usw.) kann man es wieder.

z.B.wenn der Grenzwert 10 (mySQL Profil begrenzen), und jede Anwendung so konfiguriert wurde, verwenden Sie ein Maximum von 10, die es werden 20 versuche, verbindungen.Dies ist offensichtlich eine schlechte situation.

Die Lösung ist RTFM und setzen Sie die Anschluss details in der richtigen Stelle.Dieser macht gemeinsame Veröffentlichung ein Schmerz, aber es gibt Möglichkeiten, um es (wie die Verlinkung auf andere xml-Dateien aus dem Kontext).

Nur eindeutig sein:Ich legte die Verbindung in den details WEB.xml für jede app und die hatten einen Streit darüber.

Andere Tipps

Sie scheinen zu werden, schließen Sie die Verbindung korrekt - außer für den Fall, wo prepStmt.close() throws SQLException, ich kann nicht finden, eine Verbindung undicht.

Was pool-Implementierung verwenden Sie?Beim schließen einer Verbindung, die pool müssen nicht schließen Sie die zugrunde liegende MySQL-Verbindung " sofort - nach alle, dass ist der Punkt, der einen Verbindungs-pool!So aus der MySQL-Seite, die verbindungen Aussehen würde, am Leben, obwohl Ihre app ist nicht mit jedem;Sie könnten einfach gehalten werden durch die TC-Verbindung pool.

Möchten Sie vielleicht Experimentieren Sie mit den Einstellungen der connection pool.Fragen Sie, es zu schrumpfen, der pool, wenn das system im Leerlauf ist.Oder, Fragen Sie es, aktualisieren Sie alle verbindungen in regelmäßigen Abständen.Oder, eine strenge Obere Grenze für die Anzahl der gleichzeitigen verbindungen, die es jemals bekommt von MySQL etc.

Ein Weg, um zu überprüfen, ob Ihr code hat eine Verbindung undicht ist die Kraft die ds.getConnection() immer geöffnet, eine neue physische Verbindung und conn.schließen (), um die Verbindung zu lösen (wenn Ihre Verbindung pool Einstellungen für diese).Wenn Sie dann beobachten Sie die Anschlüsse auf der MySQL-Seite, könnten Sie in der Lage sein, herauszufinden, ob der code wirklich eine Verbindung undicht ist oder nicht.

Dies ist eine ähnliche Frage - Einstellungen für den Verbindungspool für Tomcat

Dies ist meine Antwort auf diese Frage und das problem behoben für den anderen Kerl.Es kann Ihnen helfen, auch.

In Der Tomcat-Dokumentation

DBCP verwendet die Jakarta-Commons-Datenbank-Verbindungspool.Er beruht auf der Anzahl der Jakarta-Commons-Komponenten:

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

Ich bin mit dem gleichen Verbindungs-pooling Zeug, und ich werde diese Eigenschaften verhindern, dass die gleiche Sache, es ist einfach nicht so konfiguriert, durch tomcat.Aber wenn das erste, was nicht funktioniert, versuchen diese.

testWhileIdle=true
timeBetweenEvictionRunsMillis=300000

Ok, ich hätte es gelöst.Ich habe die Datenbank geändert config-Ressource, auf der folgenden sein:

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

Dies funktioniert gut genug für jetzt.Was passiert, ist, soweit ich weiß, ist, dass ich einmal erreichen die zehn verbindungen dann Tomcat ist die überprüfung für abgebrochene verbindungen (idle time > 3).Es tut dies in einem batch-job zu jeder Zeit, die max verbindungen erreicht ist.Das potenzielle Problem mit diesem ist, wenn ich benötigen Sie mehr als 10 Abfragen gleichzeitig ausgeführt (nicht nur für mich).Das wichtigste ist, dass removeAbandonedTimeout ist weniger als maxWait.

Ist es das, was geschehen sollte?ie Ist dies die Art und Weise, die den pool bedient werden soll?Wenn es ist, scheint, zumindest für mich,, dass Sie würde warten, bis etwas (die Verbindung) kaputt ist, bevor die Reparatur eher als nicht, dass es 'break' in den ersten Platz.Vielleicht bin ich immer noch nicht bekommen es.

Eine Sache, die @binil verpasst haben, sind Sie nicht schließen Sie das ResultSet im Fall einer Ausnahme.Je nach Treiber-Implementierung dies kann bewirken, dass die Verbindung offen bleiben.Bewegen Sie das Ergebnis.close () - Aufruf an den finally-block.

Ich bin mit der gleichen Konfiguration, wie Sie sind.Wenn die Verbindung im mysql-administrator(windows) zeigt, dass es in den Schlaf Modus, es bedeutet nur, dass fließen aber nicht in Gebrauch.Ich habe diesen läuft ein test-Programm mit mehreren threads zu, dass zufällige Abfragen auf Mysql.wenn es hilft, hier ist meine Konfiguration:

        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"/>
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top