Để ngăn chặn rò rỉ bộ nhớ, Trình điều khiển JDBC đã bị hủy đăng ký


325

Tôi nhận được thông báo này khi tôi chạy ứng dụng web của mình. Nó chạy tốt nhưng tôi nhận được tin nhắn này trong khi tắt máy.

SEVERE: Một ứng dụng web đã đăng ký trình điều khiển JBDC [oracle.jdbc.driver.OracleDriver] nhưng không thể hủy đăng ký khi ứng dụng web bị dừng. Để ngăn chặn rò rỉ bộ nhớ, Trình điều khiển JDBC đã không được đăng ký.

Bất kỳ trợ giúp đánh giá cao.


4
Có thể là bản sao của stackoverflow.com/questions/2604630/ Cách
skaffman

Câu trả lời:


301

Kể từ phiên bản 6.0.24, Tomcat có tính năng phát hiện rò rỉ bộ nhớ , do đó có thể dẫn đến loại thông báo cảnh báo này khi có trình điều khiển tương thích JDBC 4.0 trong ứng dụng web /WEB-INF/libtự động đăng ký khi khởi động ứng dụng web bằng ServiceLoaderAPI , nhưng đã không tự động hủy đăng ký trong thời gian tắt ứng dụng web. Thông báo này hoàn toàn không chính thức, Tomcat đã thực hiện hành động ngăn chặn rò rỉ bộ nhớ tương ứng.

Bạn có thể làm gì?

  1. Bỏ qua những cảnh báo đó. Tomcat đang làm đúng công việc của mình. Lỗi thực tế nằm ở mã của người khác (trình điều khiển JDBC đang đề cập), không phải ở lỗi của bạn. Hãy vui mừng vì Tomcat đã thực hiện đúng công việc của mình và đợi cho đến khi nhà cung cấp trình điều khiển JDBC sửa lỗi để bạn có thể nâng cấp trình điều khiển. Mặt khác, bạn không cần phải bỏ trình điều khiển JDBC trong ứng dụng web /WEB-INF/lib, nhưng chỉ trong máy chủ /lib. Nếu bạn vẫn giữ nó trong ứng dụng web /WEB-INF/lib, thì bạn nên đăng ký thủ công và hủy đăng ký bằng cách sử dụng a ServletContextListener.

  2. Hạ cấp xuống Tomcat 6.0,23 trở lên để bạn không bị làm phiền với những cảnh báo đó. Nhưng nó sẽ âm thầm giữ bộ nhớ bị rò rỉ. Không chắc chắn nếu đó là tốt để biết sau tất cả. Những loại rò rỉ bộ nhớ là một trong những nguyên nhân chính đằng sau OutOfMemoryErrorcác vấn đề trong quá trình làm việc nóng của Tomcat.

  3. Di chuyển trình điều khiển JDBC vào /libthư mục của Tomcat và có nguồn dữ liệu được kết nối để quản lý trình điều khiển. Lưu ý rằng DBCP dựng sẵn của Tomcat không hủy đăng ký trình điều khiển đúng cách. Xem thêm lỗi DBCP-322 được đóng dưới dạng WONTFIX. Bạn muốn thay thế DBCP bằng một nhóm kết nối khác đang hoạt động tốt hơn DBCP. Ví dụ: HikariCP , BoneCP hoặc có lẽ là Tomcat JDBC Pool .


25
Đây là lời khuyên tốt. Đó không phải là cảnh báo về rò rỉ bộ nhớ, đó là một cảnh báo rằng Tomcat đã thực hiện một số hành động cưỡng bức để ngăn chặn rò rỉ
matt b

49
Nếu tùy chọn (1) là cách để đi, tại sao Tomcat lại ghi những thứ này là SEVERE? SEVERE với tôi có nghĩa là "trang quản trị viên", không phải "bỏ qua".
Peter Becker

7
Tại sao không tự làm điều đó - thay vì mong đợi Tomcat làm điều đó. Theo tôi, đó không phải là công việc của Tomcat để dọn sạch mã lộn xộn của chúng tôi. Xem câu trả lời của tôi dưới đây.
Sparkyspider

2
@sproketboy: Hả? Bạn đã chỉ định các tạo phẩm JDBC là các trường của một lớp được lưu trữ lần lượt trong phiên HTTP chưa?
BalusC

2
Tôi đoán đó thường là lý do 3 (có thư viện trong wAR trái ngược với lib).
lapo

160

Trong phương thức trình nghe ngữ cảnh servlet của bạn, phương thức bối cảnhDestroyed (), tự hủy đăng ký các trình điều khiển:

// 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
Nó hoạt động! javabeat.net/servletcontextlistener-example có thể giúp triển khai trình nghe ngữ cảnh của servlet
Vadim Zin4uk

17
Điều này có khả năng không an toàn trong môi trường dùng chung vì bạn có thể không muốn hủy đăng ký tất cả các trình điều khiển JDBC có sẵn. Xem câu trả lời của tôi cho một cách tiếp cận an toàn hơn.
daiscog

85

Mặc dù Tomcat buộc phải hủy đăng ký trình điều khiển JDBC cho bạn, nhưng dù sao, việc dọn sạch tất cả các tài nguyên được tạo bởi ứng dụng web của bạn để phá hủy ngữ cảnh trong trường hợp bạn chuyển sang một thùng chứa servlet khác không thực hiện kiểm tra chống rò rỉ bộ nhớ mà Tomcat thực hiện.

Tuy nhiên, phương pháp hủy đăng ký lái xe chăn là nguy hiểm. Một số trình điều khiển được trả lại bởiDriverManager.getDrivers() phương thức có thể đã được tải bởi ClassLoader gốc (nghĩa là trình nạp lớp của trình phục vụ) không phải là ClassLoader của bối cảnh ứng dụng web (ví dụ: chúng có thể nằm trong thư mục lib của trình chứa, chứ không phải được chia sẻ trên toàn bộ vùng chứa ). Việc hủy đăng ký này sẽ ảnh hưởng đến bất kỳ ứng dụng web nào khác có thể đang sử dụng chúng (hoặc thậm chí chính container).

Do đó, người ta nên kiểm tra xem ClassLoader cho mỗi trình điều khiển có phải là ClassLoader của ứng dụng web trước khi hủy đăng ký nó không. Vì vậy, trong phương thức contextDestroyed () của ContextListener của bạn:

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

Không nên if (cl.equals(driver.getClass().getClassLoader())) {?
dùng11153

6
@ user11153 Không, chúng tôi đang kiểm tra xem nó có chính xác là cùng một thể hiện ClassLoader không, nếu đó là hai trường hợp riêng biệt có giá trị như nhau.
daiscog

4
Mặc dù những người khác dường như xử lý chính xác vấn đề đang được đề cập, nhưng chúng gây ra sự cố khi tệp chiến tranh bị xóa và sau đó được thay thế. Trong trường hợp đó, các trình điều khiển đã được đăng ký lại và không bao giờ quay lại - chỉ khởi động lại Tomcat có thể giúp bạn thoát khỏi lỗ hổng đó. Giải pháp này tránh được địa ngục đó.
OldCurmudgeon

Ở đây hầu hết đều giống nhau nhưng có thêm mã xử lý MySQL / MariaDB github.com/spring-projects/spring-boot/issues/2612
gavenkoa

2
Nếu bạn sử dụng H2 hoặc PostgreSQL, điều này dẫn đến trình điều khiển không được đăng ký lại khi tải lại. Cả hai trình điều khiển duy trì trạng thái đăng ký nội bộ không bị xóa nếu trình điều khiển chỉ được hủy đăng ký khỏi DriverManager. Tôi đã để lại một bình luận chi tiết hơn tại github.com/spring-projects/spring-boot/issues/ mẹo
Marcel Stor

26

Tôi thấy vấn đề này đi lên rất nhiều. Vâng, Tomcat 7 không tự động hủy đăng ký nó, nhưng nó THỰC SỰ kiểm soát mã của bạn và thực hành mã hóa tốt? Chắc chắn BẠN muốn biết rằng bạn có tất cả các mã chính xác để đóng tất cả các đối tượng của bạn, tắt các luồng nhóm kết nối cơ sở dữ liệu và thoát khỏi tất cả các cảnh báo. Tôi chắc chắn.

Đây là cách tôi làm điều đó.

Bước 1: Đăng ký người nghe

web.xml

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

Bước 2: Thực hiện Trình nghe

com.mysite.MyecialListener.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;
    }

}

Xin vui lòng bình luận và / hoặc thêm ...


4
Nhưng DataSourceKHÔNG có closephương pháp
Jim

9
nó có nên thực hiện javax.servlet.ServletContextListener, không mở rộng ApplicationContextListener không?
egaga

2
Có một lý do cho thứ tự của các hoạt động trong phương thức contextDestroyed? Tại sao bạn làm bước 1. trước khi thực hiện bước 2., nơi initContext, envContextdatasourcekhông được tham chiếu tại tất cả? Tôi đang hỏi vì tôi không hiểu bước 3.
matthaeus

4
@matthaeus Tôi nghĩ Bước 1. không cần thiết, lookupdường như chỉ cần lấy một số đối tượng bạn không cần. Bước 3. hoàn toàn vô dụng. Nó chắc chắn không thêm bất kỳ sự an toàn nào và có vẻ như một người mới bắt đầu sẽ không hiểu cách thức hoạt động của GC. Tôi sẽ chỉ đi với stackoverflow.com/a/5315467/897024 và xóa tất cả các trình điều khiển.
kapex

4
@kapep Xóa tất cả các trình điều khiển là nguy hiểm vì một số trình điều khiển có thể được chia sẻ trên container. Xem câu trả lời của tôi để biết cách tiếp cận chỉ loại bỏ các trình điều khiển được tải bởi ClassLoader của ứng dụng web của bạn.
daiscog

14

Đây hoàn toàn là vấn đề đăng ký / hủy đăng ký trình điều khiển trong trình điều khiển của mysql hoặc trình tải lớp ứng dụng web tomcats. Sao chép trình điều khiển mysql vào thư mục lib tomcats (vì vậy nó được tải trực tiếp bởi jvm chứ không phải bởi tomcat) và thông báo sẽ biến mất. Điều đó làm cho trình điều khiển mysdb jdbc chỉ được tải khi tắt JVM và sau đó không ai quan tâm đến việc rò rỉ bộ nhớ.


2
không hoạt động ... Tôi đã cố gắng sao chép trình điều khiển jdbc mà bạn nói: TOMCAT_HOME / lib / postgresql-9.0-801.jdbc4.jar - Tomcat 7.0 \ lib \ postgresql-9.0-801.jdbc4.jar không có kết quả ...
FAjir

5
@Florito - bạn cũng phải xóa nó khỏi ứng dụng web WEB-INF / lib của mình
Collin Peters

8

Nếu bạn nhận được thông báo này từ một cuộc chiến do Maven xây dựng, hãy thay đổi phạm vi của trình điều khiển JDBC để cung cấp và đặt một bản sao của nó trong thư mục lib. Như thế này:

<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

Giải pháp cho việc triển khai trên mỗi ứng dụng

Đây là một trình lắng nghe tôi đã viết để giải quyết vấn đề: nó tự động phát hiện nếu trình điều khiển đã tự đăng ký và hành động tương ứng.

Quan trọng: nó chỉ được sử dụng khi jar trình điều khiển được triển khai trong WEB-INF / lib , không phải trong Tomcat / lib, như nhiều người đề xuất, để mỗi ứng dụng có thể chăm sóc trình điều khiển riêng của mình và chạy trên Tomcat chưa được chạm . Đó là cách nó phải là IMHO.

Chỉ cần định cấu hình trình nghe trong tệp webDB của bạn trước bất kỳ tệp nào khác và thưởng thức.

thêm gần đầu web.xml :

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

lưu dưới dạng 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");
        }

    }

}

Mẹo: Kể từ Servlet 3.0, bạn có thể chú thích lớp của mình @WebListenervà bỏ qua web.xmlcấu hình.
Basil Bourque

Đúng, chỉ cần đảm bảo rằng nó được chọn với mức độ ưu tiên đủ cao, để không ai cần sử dụng trình điều khiển trước hoặc sau.
Andrea Ratto

6

Tôi sẽ thêm vào cái này một cái gì đó tôi tìm thấy trên các diễn đàn mùa xuân. Nếu bạn di chuyển jar trình điều khiển JDBC của mình sang thư mục lib tomcat, thay vì triển khai nó với ứng dụng web của bạn, cảnh báo dường như biến mất. Tôi có thể xác nhận rằng điều này làm việc cho tôi

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


1
Tôi nghĩ rằng điều này cung cấp một giải pháp tốt hơn - chỉ cần phân lớp DatasourceManager của bạn và ghi đè phương thức đóng để thêm sự hủy đăng ký. Sau đó, Spring sẽ xử lý nó khi nó phá hủy bối cảnh của nó và Tomcat sẽ không cung cấp cho bạn nhật ký SEVERE và bạn không phải chuyển trình điều khiển JDBC của mình vào thư mục lib. Đây là thông điệp gốc từ diễn đàn mùa xuân cũ
Adam

6

Tôi thấy rằng việc thực hiện một phương thức hủy () đơn giản để hủy đăng ký bất kỳ trình điều khiển JDBC nào hoạt động tốt.

/**
 * 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
Điều này có khả năng không an toàn trong môi trường dùng chung vì bạn có thể không muốn hủy đăng ký tất cả các trình điều khiển JDBC có sẵn. Xem câu trả lời của tôi cho một cách tiếp cận an toàn hơn. Ngoài ra, điều này thực sự nên được thực hiện trong ServletContextListener, chứ không phải trên cơ sở mỗi servlet vì trình điều khiển JDBC của bạn được chia sẻ trên tất cả các máy chủ của bạn trong ứng dụng web của bạn.
daiscog

3

Để ngăn chặn rò rỉ bộ nhớ này, chỉ cần hủy đăng ký trình điều khiển khi tắt ngữ cảnh.

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>

Nguồn cảm hứng cho tôi để sửa lỗi này.


2

Tôi đã gặp một vấn đề tương tự, nhưng ngoài ra, tôi đã gặp lỗi Java Heap Space bất cứ khi nào tôi sửa đổi / lưu các trang JSP với máy chủ Tomcat đang chạy, do đó bối cảnh không được sạc lại đầy đủ.

Các phiên bản của tôi là Apache Tomcat 6.0,29 và JDK 6u12.

Nâng cấp JDK lên 6u21 như được đề xuất trong phần Tài liệu tham khảo của URL http://wiki.apache.org/tomcat/MemoryLeakProtection đã giải quyết vấn đề Java Heap Space (bối cảnh hiện tải lại OK) mặc dù lỗi Trình điều khiển JDBC vẫn xuất hiện.


0

Tôi thấy vấn đề tương tự với Tomcat phiên bản 6.026.

Tôi đã sử dụng Mysql JDBC.jar trong Thư viện WebAPP cũng như trong TOMCAT Lib.

Để khắc phục lỗi trên bằng cách xóa Jar khỏi thư mục lib TOMCAT.

Vì vậy, điều tôi hiểu là TOMCAT đang xử lý rò rỉ bộ nhớ JDBC đúng cách. Nhưng nếu bình MdbQL Jdbc được sao chép trong WebApp và Tomcat Lib, Tomcat sẽ chỉ có thể xử lý tệp jar có trong thư mục Tomcat Lib.


0

Tôi đã gặp phải vấn đề này khi tôi đang triển khai ứng dụng Grails của mình trên AWS. Đây là vấn đề của trình điều khiển org.h2 mặc định của trình điều khiển JDBC . Như bạn có thể thấy điều này trong Datasource.groovy trong thư mục cấu hình của bạn. Như bạn có thể thấy dưới đây:

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

Nhận xét những dòng đó bất cứ nơi nào có đề cập org.h2.Driver trong , nếu bạn không sử dụng cơ sở dữ liệu đó. Nếu không, bạn phải tải về tệp jar cơ sở dữ liệu.

Cảm ơn .


0

Lỗi này xảy ra với tôi trong Ứng dụng Grails với Trình điều khiển JTDS 1.3.0 (Máy chủ SQL). Vấn đề là đăng nhập không chính xác trong SQL Server. Sau khi giải quyết vấn đề này (trong SQL Server), ứng dụng của tôi đã được triển khai chính xác trong Tomcat. Mẹo: Tôi thấy lỗi trong stacktrace.log

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.