tutorial example configurar java tomcat jdbc

java - configurar - tomcat jdbc connection pool example



Para evitar una pérdida de memoria, el controlador JDBC ha sido anulado por la fuerza (14)

Solución para implementaciones por aplicación

Este es un oyente que escribí para resolver el problema: se detecta automáticamente si el controlador se ha registrado y actúa en consecuencia.

Importante: debe utilizarse SÓLO cuando el controlador jar se implementa en WEB-INF / lib , no en Tomcat / lib, como muchos sugieren, para que cada aplicación pueda ocuparse de su propio controlador y ejecutarse en un Tomcat intacto. . Esa es la forma en que debería ser IMHO.

Simplemente configure el oyente en su web.xml antes de cualquier otro y disfrute.

agregar cerca de la parte superior de web.xml :

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

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

Recibo este mensaje cuando ejecuto mi aplicación web. Funciona bien, pero recibo este mensaje durante el cierre.

GRAVE: una aplicación web registró el controlador JBDC [oracle.jdbc.driver.OracleDriver] pero no pudo anular el registro cuando se detuvo la aplicación web. Para evitar una pérdida de memoria, el controlador JDBC no se ha registrado.

Cualquier ayuda apreciada.


Para evitar esta pérdida de memoria, simplemente cancele el registro del controlador al cerrar el contexto.

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>

github.com/spring-projects/spring-boot/issues/2612 que me inspiró para esta corrección de errores.



Al eliminar la aplicación (tomcat6) se resuelve. Los archivos conf se conservan. Se rompe de alguna manera. No estoy muy seguro de cómo lo hace.


Descubrí que la implementación de un método simple de destruir () para anular el registro de cualquier controlador JDBC funciona bien.

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


En su método contextDestroyed () de escucha de contexto de servlet, cancele el registro manualmente de los controladores:

// 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); } }


Encontré el mismo problema con Tomcat versión 6.026.

Utilicé Mysql JDBC.jar en la biblioteca WebAPP, así como en TOMCAT Lib.

Para arreglar lo anterior, elimine el Jar de la carpeta lib de TOMCAT.

Entonces, lo que entiendo es que TOMCAT está manejando la pérdida de memoria JDBC correctamente. Pero si el jar de MYSQL Jdbc está duplicado en la aplicación web y Tomcat Lib, Tomcat solo podrá manejar el tarro presente en la carpeta de Tomcat Lib.


Estaba teniendo un problema similar, pero además recibía un error de Java Heap Space cada vez que modificaba / guardaba las páginas JSP con el servidor Tomcat en ejecución, por lo que el contexto no estaba completamente recargado.

Mis versiones fueron Apache Tomcat 6.0.29 y JDK 6u12.

La actualización de JDK a 6u21 como se sugiere en la sección Referencias de la URL http://wiki.apache.org/tomcat/MemoryLeakProtection solucionó el problema del espacio de almacenamiento dinámico de Java (el contexto ahora se vuelve a cargar correctamente), aunque el error del controlador JDBC sigue apareciendo.


Este es un problema puramente de registro / desregistro de controladores en mysql`s driver o tomcats webapp-classloader. Copie el controlador mysql en la carpeta lib de tomcats (para que se cargue directamente por jvm, no por tomcat), y el mensaje desaparecerá. Eso hace que el controlador mysql jdbc se descargue solo en el cierre de JVM, y nadie se preocupa por las fugas de memoria.


He enfrentado este problema cuando estaba implementando mi aplicación Grails en AWS. Esto es cuestión del controlador org.h2 del controlador predeterminado de JDBC. Como puede ver esto en Datasource.groovy dentro de su carpeta de configuración. Como puede ver abajo :

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

Comente esas líneas siempre que se mencione org.h2.Driver en el archivo datasource.groovy, si no está usando esa base de datos. De lo contrario tienes que descargar ese archivo jar de base de datos.

Gracias .


Si bien Tomcat anula el registro del controlador JDBC por la fuerza, no obstante, es una buena práctica limpiar todos los recursos creados por su aplicación web para la destrucción del contexto en caso de que se mueva a otro contenedor de servlets que no realice las comprobaciones de prevención de fugas de memoria que realiza Tomcat.

Sin embargo, la metodología de desregistro de conductor general es peligrosa. Algunos controladores devueltos por el método DriverManager.getDrivers() pueden haber sido cargados por el ClassLoader principal (es decir, el cargador de clases del contenedor del servlet) no por el ClassLoader del contexto de la aplicación web (por ejemplo, pueden estar en la carpeta lib del contenedor, no la aplicación de la aplicación web, y por lo tanto compartido a través de todo el contenedor). La anulación del registro de estos afectará a cualquier otra aplicación web que pueda estar usándolos (o incluso al contenedor en sí).

Por lo tanto, uno debe verificar que el ClassLoader para cada controlador sea el ClassLoader de la aplicación web antes de desregistrarlo. Por lo tanto, en el método contextDestroyed () de 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); } } }


Si recibe este mensaje de una guerra construida por Maven, cambie el alcance del controlador JDBC al proporcionado, y coloque una copia en el directorio lib. Me gusta esto:

<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>


Veo que este tema surge mucho. Sí, Tomcat 7 lo elimina automáticamente, pero ¿es eso REALMENTE tomar el control de su código y una buena práctica de codificación? Seguramente USTED desea saber que tiene todo el código correcto para cerrar todos sus objetos, cerrar los subprocesos de la agrupación de conexiones de la base de datos y eliminar todas las advertencias. Ciertamente lo hago

Así es como lo hago.

Paso 1: Registrar un Oyente

web.xml

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

Paso 2: Implementar el Oyente

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; } }

Por favor, siéntase libre de comentar y / o agregar ...


Desde la versión 6.0.24, Tomcat viene con una función de detección de fugas de memoria , que a su vez puede generar este tipo de mensajes de advertencia cuando hay un controlador compatible con JDBC 4.0 en la aplicación /WEB-INF/lib que se registers automáticamente durante el inicio de la aplicación. utilizando la API de ServiceLoader , pero que no se auto- deregister durante el cierre de la aplicación web. Este mensaje es puramente informal, Tomcat ya ha tomado la acción de prevención de pérdida de memoria en consecuencia.

¿Qué puedes hacer?

  1. Ignora esas advertencias. Tomcat está haciendo bien su trabajo. El error real está en el código de otra persona (el controlador JDBC en cuestión), no en el suyo. Sea feliz de que Tomcat haya hecho su trabajo correctamente y espere hasta que el proveedor del controlador JDBC lo arregle para que pueda actualizar el controlador. Por otro lado, no se supone que se caiga un controlador JDBC en /WEB-INF/lib , sino solo en el servidor /lib . Si aún lo mantiene en la aplicación web /WEB-INF/lib , entonces debe registrarlo manualmente y cancelar su registro utilizando un ServletContextListener .

  2. Cambie de categoría a Tomcat 6.0.23 o superior para que no se moleste con esas advertencias. Pero seguirá guardando silencio la memoria. No estoy seguro si es bueno saberlo después de todo. Ese tipo de fugas de memoria es una de las principales causas detrás de los problemas de OutOfMemoryError durante las implementaciones de Tomcat.

  3. Mueva el controlador JDBC a la carpeta /lib Tomcat y tenga una fuente de datos agrupada de conexión para administrar el controlador. Tenga en cuenta que el DBCP integrado de Tomcat no elimina el registro de los controladores correctamente al cerrarse. Véase también el error DBCP-322 que está cerrado como WONTFIX. Prefiere reemplazar DBCP por otro grupo de conexiones que está haciendo su trabajo mejor que DBCP. Por ejemplo, HikariCP , BoneCP , o tal vez Tomcat JDBC Pool .