Um einen Speicherverlust zu verhindern, wurde der JDBC-Treiber zwangsweise abgemeldet


325

Ich erhalte diese Meldung, wenn ich meine Webanwendung ausführe. Es läuft gut, aber ich bekomme diese Meldung beim Herunterfahren.

SCHWER: Eine Webanwendung hat den JBDC-Treiber [oracle.jdbc.driver.OracleDriver] registriert, die Registrierung konnte jedoch nicht aufgehoben werden, als die Webanwendung gestoppt wurde. Um einen Speicherverlust zu verhindern, wurde der JDBC-Treiber zwangsweise abgemeldet.

Jede Hilfe geschätzt.


Antworten:


301

Seit Version 6.0.24 wird Tomcat mit einer Speicherleckerkennungsfunktion ausgeliefert , die wiederum zu solchen Warnmeldungen führen kann, wenn sich in den Webanwendungen ein JDBC 4.0-kompatibler Treiber befindet, /WEB-INF/libder sich beim Start der Webanwendung mithilfe der API automatisch registriert , der jedoch hat sich beim Herunterfahren der Webapp nicht automatisch abgemeldet . Diese Nachricht ist rein informell. Tomcat hat die Maßnahme zur Verhinderung von Speicherlecks bereits entsprechend ergriffen.ServiceLoader

Was kannst du tun?

  1. Ignorieren Sie diese Warnungen. Tomcat macht seinen Job richtig. Der eigentliche Fehler liegt im Code einer anderen Person (dem fraglichen JDBC-Treiber) und nicht in Ihrem. Seien Sie froh, dass Tomcat seine Arbeit ordnungsgemäß ausgeführt hat, und warten Sie, bis der Hersteller des JDBC-Treibers das Problem behoben hat, damit Sie den Treiber aktualisieren können. Auf der anderen Seite sollten Sie keinen JDBC-Treiber in Webanwendungen ablegen /WEB-INF/lib, sondern nur in Servern /lib. Wenn Sie es weiterhin in der Webanwendung behalten /WEB-INF/lib, sollten Sie es manuell registrieren und mit einem abmelden ServletContextListener.

  2. Downgrade auf Tomcat 6.0.23 oder älter, damit Sie nicht mit diesen Warnungen belästigt werden. Aber es wird stillschweigend Speicher verlieren. Ich bin mir nicht sicher, ob das gut zu wissen ist. Diese Art von Speicherlecks sind eine der Hauptursachen für OutOfMemoryErrorProbleme bei Tomcat-Hotdeployments.

  3. Verschieben Sie den JDBC-Treiber in den Tomcat- /libOrdner und verfügen Sie über eine Datenquelle mit Verbindungspool, um den Treiber zu verwalten. Beachten Sie, dass das in Tomcat integrierte DBCP die Treiber beim Schließen nicht ordnungsgemäß abmeldet. Siehe auch Fehler DBCP-322, der als WONTFIX geschlossen ist. Sie möchten DBCP lieber durch einen anderen Verbindungspool ersetzen, der seine Aufgabe besser erfüllt als DBCP. Zum Beispiel HikariCP , BoneCP oder vielleicht Tomcat JDBC Pool .


25
Das ist ein guter Rat. Es ist keine Warnung vor einem Speicherverlust, es ist eine Warnung, dass Tomcat gewaltsame Maßnahmen ergriffen hat, um ein Leck zu verhindern
matt b

49
Wenn Option (1) der richtige Weg ist, warum protokolliert Tomcat diese jedoch als SEVERE? SEVERE bedeutet für mich "Page the Admin", nicht "Ignorieren".
Peter Becker

7
Warum nicht selbst machen - anstatt zu erwarten, dass Tomcat es macht. Meiner Meinung nach ist es nicht Tomcats Aufgabe, unseren unordentlichen Code zu bereinigen. Siehe meine Antwort unten.
Sparkyspider

2
@sproketboy: Huh? Haben Sie JDBC-Artefakte als Felder einer Klasse zugewiesen, die wiederum in der HTTP-Sitzung gespeichert ist?
BalusC

2
Ich denke, es ist normalerweise Grund 3 (die Bibliothek im WAR zu haben, im Gegensatz zu lib).
Lapo

160

Melden Sie die Treiber in der KontextDestroyed () -Methode Ihres Servlet-Kontext-Listeners manuell ab:

// This manually deregisters JDBC driver, which prevents Tomcat 7 from complaining about memory leaks wrto this class
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
    Driver driver = drivers.nextElement();
    try {
        DriverManager.deregisterDriver(driver);
        LOG.log(Level.INFO, String.format("deregistering jdbc driver: %s", driver));
    } catch (SQLException e) {
        LOG.log(Level.SEVERE, String.format("Error deregistering driver %s", driver), e);
    }
}

3
Es klappt! javabeat.net/servletcontextlistener-example kann helfen, Servlet-Kontext-Listener zu implementieren
Vadim Zin4uk

17
Dies ist in einer gemeinsam genutzten Umgebung möglicherweise unsicher, da Sie möglicherweise nicht alle verfügbaren JDBC-Treiber abmelden möchten . Siehe meine Antwort für einen sichereren Ansatz.
Daiscog

84

Obwohl Tomcat den JDBC-Treiber für Sie zwangsweise abmeldet, empfiehlt es sich dennoch, alle von Ihrer Webanwendung bei Kontextzerstörung erstellten Ressourcen zu bereinigen, falls Sie in einen anderen Servlet-Container wechseln, der die von Tomcat durchgeführten Überprüfungen zur Verhinderung von Speicherlecks nicht durchführt.

Die Methode der pauschalen Abmeldung von Treibern ist jedoch gefährlich. Einige von der DriverManager.getDrivers()Methode zurückgegebene Treiber wurden möglicherweise vom übergeordneten ClassLoader (dh dem Classloader des Servlet-Containers) und nicht vom ClassLoader des Webapp-Kontexts geladen (z. B. befinden sie sich möglicherweise im lib-Ordner des Containers, nicht im Webapp-Ordner, und werden daher für den gesamten Container freigegeben ). Die Abmeldung dieser wirkt sich auf alle anderen Webanwendungen aus, die sie möglicherweise verwenden (oder sogar auf den Container selbst).

Daher sollte überprüft werden, ob der ClassLoader für jeden Treiber der ClassLoader der Webanwendung ist, bevor die Registrierung aufgehoben wird. In der contextDestroyed () -Methode Ihres ContextListener:

public final void contextDestroyed(ServletContextEvent sce) {
    // ... First close any background tasks which may be using the DB ...
    // ... Then close any DB connection pools ...

    // Now deregister JDBC drivers in this context's ClassLoader:
    // Get the webapp's ClassLoader
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    // Loop through all drivers
    Enumeration<Driver> drivers = DriverManager.getDrivers();
    while (drivers.hasMoreElements()) {
        Driver driver = drivers.nextElement();
        if (driver.getClass().getClassLoader() == cl) {
            // This driver was registered by the webapp's ClassLoader, so deregister it:
            try {
                log.info("Deregistering JDBC driver {}", driver);
                DriverManager.deregisterDriver(driver);
            } catch (SQLException ex) {
                log.error("Error deregistering JDBC driver {}", driver, ex);
            }
        } else {
            // driver was not registered by the webapp's ClassLoader and may be in use elsewhere
            log.trace("Not deregistering JDBC driver {} as it does not belong to this webapp's ClassLoader", driver);
        }
    }
}

Sollte nicht sein if (cl.equals(driver.getClass().getClassLoader())) {?
user11153

6
@ user11153 Nein, wir prüfen, ob es sich genau um dieselbe ClassLoader-Instanz handelt, nicht ob es sich um zwei separate Instanzen handelt, deren Wert gleich ist.
Daiscog

4
Obwohl die anderen das betreffende Problem richtig zu behandeln scheinen, verursachen sie Probleme, wenn die Kriegsdatei gelöscht und dann ersetzt wird. In diesem Fall sind die Treiber abgemeldet und kehren nie zurück - nur ein Tomcat-Neustart kann Sie aus dieser Lücke herausholen. Diese Lösung vermeidet diese Hölle.
OldCurmudgeon

Hier meistens gleich, aber mit zusätzlichem MySQL / MariaDB-Bearbeitungscode github.com/spring-projects/spring-boot/issues/2612
gavenkoa

2
Wenn Sie H2 oder PostgreSQL verwenden, wird der Treiber beim erneuten Laden nicht erneut registriert. Beide Treiber behalten einen internen Registrierungsstatus bei, der nicht gelöscht wird, wenn der Treiber nur von der abgemeldet wird DriverManager. Ich habe einen ausführlicheren Kommentar unter github.com/spring-projects/spring-boot/issues/…
Marcel Stör

26

Ich sehe, dass dieses Problem häufig auftritt. Ja, Tomcat 7 hebt die Registrierung automatisch auf, aber übernimmt es WIRKLICH die Kontrolle über Ihren Code und eine gute Codierungspraxis? Sicherlich möchten SIE wissen, dass Sie über den richtigen Code verfügen, um alle Ihre Objekte zu schließen, Threads des Datenbankverbindungspools herunterzufahren und alle Warnungen zu entfernen. Das tue ich auf jeden Fall.

So mache ich es.

Schritt 1: Registrieren Sie einen Listener

web.xml

<listener>
    <listener-class>com.mysite.MySpecialListener</listener-class>
</listener>

Schritt 2: Implementieren Sie den Listener

com.mysite.MySpecialListener.java

public class MySpecialListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        // On Application Startup, please…

        // Usually I'll make a singleton in here, set up my pool, etc.
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        // On Application Shutdown, please…

        // 1. Go fetch that DataSource
        Context initContext = new InitialContext();
        Context envContext  = (Context)initContext.lookup("java:/comp/env");
        DataSource datasource = (DataSource)envContext.lookup("jdbc/database");

        // 2. Deregister Driver
        try {
            java.sql.Driver mySqlDriver = DriverManager.getDriver("jdbc:mysql://localhost:3306/");
            DriverManager.deregisterDriver(mySqlDriver);
        } catch (SQLException ex) {
            logger.info("Could not deregister driver:".concat(ex.getMessage()));
        } 

        // 3. For added safety, remove the reference to dataSource for GC to enjoy.
        dataSource = null;
    }

}

Bitte zögern Sie nicht zu kommentieren und / oder hinzuzufügen ...


4
Hat DataSourceaber KEINE closeMethode
Jim

9
sollte es javax.servlet.ServletContextListener implementieren, nicht ApplicationContextListener erweitern?
Egaga

2
Gibt es einen Grund für die Reihenfolge dieser Operationen in der Methode contextDestroyed? Warum tun Sie Schritt 1 vor dem Schritt tun 2., wo initContext, envContextund datasourcesind überhaupt nicht referenziert? Ich
frage

4
@matthaeus Ich denke, Schritt 1. ist nicht notwendig, lookupscheint nur einige Objekte zu bekommen, die Sie nicht brauchen. Schritt 3. ist völlig nutzlos. Es fügt sicherlich keine Sicherheit hinzu und sieht so aus, als würden Anfänger etwas tun, die nicht verstehen, wie GC funktioniert. Ich würde einfach mit stackoverflow.com/a/5315467/897024 gehen und alle Treiber entfernen.
Kapex

4
@kapep Das Entfernen aller Treiber ist gefährlich, da einige möglicherweise im gesamten Container geteilt werden. In meiner Antwort finden Sie einen Ansatz, bei dem nur die vom ClassLoader Ihrer Webanwendung geladenen Treiber entfernt werden.
Daiscog

14

Dies ist ein reines Problem bei der Registrierung / Abmeldung von Treibern in mysqls Treiber oder Tomcats Webapp-Classloader. Kopieren Sie den MySQL-Treiber in den Ordner "tomcats lib" (also wird er direkt von jvm geladen, nicht von tomcat), und die Nachricht wird gelöscht. Dadurch wird der MySQL-JDBC-Treiber nur beim Herunterfahren der JVM entladen, und dann kümmert sich niemand um Speicherverluste.


2
Das funktioniert nicht ... Ich habe versucht, den JDBC-Treiber zu kopieren. Sie haben gesagt: TOMCAT_HOME / lib / postgresql-9.0-801.jdbc4.jar - Tomcat 7.0 \ lib \ postgresql-9.0-801.jdbc4.jar ohne Ergebnisse ...
FAjir

5
@Florito - Sie müssen es auch aus Ihren Web-Apps WEB-INF / lib entfernen
Collin Peters

8

Wenn Sie diese Nachricht von einem von Maven erstellten Krieg erhalten, ändern Sie den Bereich des JDBC-Treibers in "Bereitgestellt" und legen Sie eine Kopie davon im lib-Verzeichnis ab. So was:

<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.18</version>
  <!-- put a copy in /usr/share/tomcat7/lib -->
  <scope>provided</scope>
</dependency>

8

Lösung für Bereitstellungen pro App

Dies ist ein Listener, den ich geschrieben habe, um das Problem zu lösen: Er erkennt automatisch, ob sich der Treiber registriert hat, und handelt entsprechend

Wichtig: Es darf NUR verwendet werden, wenn die Treiber-JAR in WEB-INF / lib bereitgestellt wird , nicht in Tomcat / lib, wie viele vermuten, damit jede Anwendung ihren eigenen Treiber pflegen und auf einem unberührten Tomcat ausführen kann . So sollte es IMHO sein.

Konfigurieren Sie einfach den Listener in Ihrer web.xml vor allen anderen und genießen Sie.

füge oben in der Datei web.xml hinzu :

<listener>
    <listener-class>utils.db.OjdbcDriverRegistrationListener</listener-class>    
</listener>

Speichern unter utils / db / OjdbcDriverRegistrationListener.java :

package utils.db;

import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import oracle.jdbc.OracleDriver;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Registers and unregisters the Oracle JDBC driver.
 * 
 * Use only when the ojdbc jar is deployed inside the webapp (not as an
 * appserver lib)
 */
public class OjdbcDriverRegistrationListener implements ServletContextListener {

    private static final Logger LOG = LoggerFactory
            .getLogger(OjdbcDriverRegistrationListener.class);

    private Driver driver = null;

    /**
     * Registers the Oracle JDBC driver
     */
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        this.driver = new OracleDriver(); // load and instantiate the class
        boolean skipRegistration = false;
        Enumeration<Driver> drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            Driver driver = drivers.nextElement();
            if (driver instanceof OracleDriver) {
                OracleDriver alreadyRegistered = (OracleDriver) driver;
                if (alreadyRegistered.getClass() == this.driver.getClass()) {
                    // same class in the VM already registered itself
                    skipRegistration = true;
                    this.driver = alreadyRegistered;
                    break;
                }
            }
        }

        try {
            if (!skipRegistration) {
                DriverManager.registerDriver(driver);
            } else {
                LOG.debug("driver was registered automatically");
            }
            LOG.info(String.format("registered jdbc driver: %s v%d.%d", driver,
                    driver.getMajorVersion(), driver.getMinorVersion()));
        } catch (SQLException e) {
            LOG.error(
                    "Error registering oracle driver: " + 
                            "database connectivity might be unavailable!",
                    e);
            throw new RuntimeException(e);
        }
    }

    /**
     * Deregisters JDBC driver
     * 
     * Prevents Tomcat 7 from complaining about memory leaks.
     */
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        if (this.driver != null) {
            try {
                DriverManager.deregisterDriver(driver);
                LOG.info(String.format("deregistering jdbc driver: %s", driver));
            } catch (SQLException e) {
                LOG.warn(
                        String.format("Error deregistering driver %s", driver),
                        e);
            }
            this.driver = null;
        } else {
            LOG.warn("No driver to deregister");
        }

    }

}

Tipp: Ab Servlet 3.0 können Sie Ihre Klasse mit Anmerkungen versehen @WebListenerund die web.xmlKonfiguration weglassen .
Basil Bourque

Stellen Sie sicher, dass es mit einer Priorität aufgenommen wird, die hoch genug ist, damit niemand den Treiber vorher oder nachher verwenden muss.
Andrea Ratto

6

Ich werde etwas hinzufügen, das ich in den Frühlingsforen gefunden habe. Wenn Sie Ihr JDBC-Treiber-JAR in den Ordner tomcat lib verschieben, anstatt es mit Ihrer Webanwendung bereitzustellen, scheint die Warnung zu verschwinden. Ich kann bestätigen, dass dies bei mir funktioniert hat

http://forum.springsource.org/showthread.php?87335-Failure-to-unregister-the-MySQL-JDBC-Driver&p=334883#post334883


1
Ich denke, dies bietet eine bessere Lösung - unterklassifizieren Sie einfach Ihren DatasourceManager und überschreiben Sie die Methode close, um die Abmeldung hinzuzufügen. Dann wird Spring damit umgehen, wenn es seinen Kontext zerstört, und Tomcat wird Ihnen das SEVERE-Protokoll nicht geben, und Sie müssen Ihren JDBC-Treiber nicht in das lib-Verzeichnis verschieben. Hier ist die ursprüngliche Nachricht aus dem alten Frühlingsforum
Adam

6

Ich fand, dass die Implementierung einer einfachen destroy () -Methode zum Abmelden von JDBC-Treibern gut funktioniert.

/**
 * Destroys the servlet cleanly by unloading JDBC drivers.
 * 
 * @see javax.servlet.GenericServlet#destroy()
 */
public void destroy() {
    String prefix = getClass().getSimpleName() +" destroy() ";
    ServletContext ctx = getServletContext();
    try {
        Enumeration<Driver> drivers = DriverManager.getDrivers();
        while(drivers.hasMoreElements()) {
            DriverManager.deregisterDriver(drivers.nextElement());
        }
    } catch(Exception e) {
        ctx.log(prefix + "Exception caught while deregistering JDBC drivers", e);
    }
    ctx.log(prefix + "complete");
}

5
Dies ist in einer gemeinsam genutzten Umgebung möglicherweise unsicher, da Sie möglicherweise nicht alle verfügbaren JDBC-Treiber abmelden möchten . Siehe meine Antwort für einen sichereren Ansatz. Dies sollte auch wirklich in einem ServletContextListener erfolgen, nicht pro Servlet, da Ihr JDBC-Treiber für alle Servlets in Ihrer Webanwendung freigegeben ist.
Daiscog

3

Um diesen Speicherverlust zu verhindern, melden Sie den Treiber beim Herunterfahren des Kontexts einfach ab.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.mywebsite</groupId>
    <artifactId>emusicstore</artifactId>
    <version>1.0-SNAPSHOT</version>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>1.9</source>
                    <target>1.9</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <!-- ... -->

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>4.0.1.Final</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.0-api</artifactId>
            <version>1.0.1.Final</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

</project>

MyWebAppContextListener.java

package com.emusicstore.utils;

import com.mysql.cj.jdbc.AbandonedConnectionCleanupThread;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;

public class MyWebAppContextListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("************** Starting up! **************");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("************** Shutting down! **************");
        System.out.println("Destroying Context...");
        System.out.println("Calling MySQL AbandonedConnectionCleanupThread checkedShutdown");
        AbandonedConnectionCleanupThread.checkedShutdown();

        ClassLoader cl = Thread.currentThread().getContextClassLoader();

        Enumeration<Driver> drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            Driver driver = drivers.nextElement();

            if (driver.getClass().getClassLoader() == cl) {
                try {
                    System.out.println("Deregistering JDBC driver {}");
                    DriverManager.deregisterDriver(driver);

                } catch (SQLException ex) {
                    System.out.println("Error deregistering JDBC driver {}");
                    ex.printStackTrace();
                }
            } else {
                System.out.println("Not deregistering JDBC driver {} as it does not belong to this webapp's ClassLoader");
            }
        }
    }

}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <listener>
        <listener-class>com.emusicstore.utils.MyWebAppContextListener</listener-class>
    </listener>

<!-- ... -->

</web-app>

Quelle , die mich zu dieser Fehlerbehebung inspiriert hat.


2

Ich hatte ein ähnliches Problem, aber zusätzlich wurde jedes Mal ein Java Heap Space-Fehler angezeigt, wenn ich JSP-Seiten bei laufendem Tomcat-Server geändert / gespeichert habe. Daher wurde der Kontext nicht vollständig aufgeladen.

Meine Versionen waren Apache Tomcat 6.0.29 und JDK 6u12.

Durch das Aktualisieren von JDK auf 6u21, wie im Abschnitt " Referenzen " der URL http://wiki.apache.org/tomcat/MemoryLeakProtection vorgeschlagen, wurde das Problem mit dem Java- Heapspeicher behoben (der Kontext wird jetzt erneut geladen, OK), obwohl der JDBC-Treiberfehler weiterhin angezeigt wird.


0

Ich habe das gleiche Problem mit Tomcat Version 6.026 gefunden.

Ich habe die MySQL-Datei JDBC.jar sowohl in der WebAPP-Bibliothek als auch in TOMCAT Lib verwendet.

Um dies zu beheben, entfernen Sie das Jar aus dem Ordner TOMCAT lib.

Ich verstehe also, dass TOMCAT den JDBC-Speicherverlust ordnungsgemäß behandelt. Wenn die MYSQL-Jdbc-JAR-Datei jedoch in WebApp und Tomcat Lib dupliziert wird, kann Tomcat nur die im Tomcat Lib-Ordner vorhandene JAR-Datei verarbeiten.


0

Ich habe dieses Problem festgestellt, als ich meine Grails-Anwendung auf AWS bereitgestellt habe. Dies ist eine Frage des JDBC-Standardtreibers org.h2 . Wie Sie in der Datei Datasource.groovy in Ihrem Konfigurationsordner sehen können. Wie Sie unten sehen können:

dataSource {
    pooled = true
    jmxExport = true
    driverClassName = "org.h2.Driver"   // make this one comment
    username = "sa"
    password = ""
}

Kommentieren Sie diese Zeilen überall dort, wo org.h2.Driver in der Datei datasource.groovy erwähnt wird, wenn Sie diese Datenbank nicht verwenden. Andernfalls müssen Sie diese Datenbank-JAR-Datei herunterladen.

Vielen Dank .


0

Dieser Fehler ist mir in einer Grails-Anwendung mit dem JTDS-Treiber 1.3.0 (SQL Server) passiert. Das Problem war eine falsche Anmeldung in SQL Server. Nachdem dieses Problem behoben wurde (in SQL Server), wurde meine App in Tomcat korrekt bereitgestellt. Tipp: Ich habe den Fehler in stacktrace.log gesehen

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.