Wildfly 20 中的数据源池连接未关闭

Datasource pool connection not closed in Wildfly 20

我有一个 Wildfly Java 应用程序 运行 MariaDB 数据库。最初连接工作正常,但在 20 个连接(默认)后,下次尝试连接服务器时挂起,大约一分钟后它抛出以下异常:

javax.resource.ResourceException: IJ000453: Unable to get managed connection for java:jboss/datasources/IndustryDS

这是我连接和关闭数据源的方式:

    private InitialContext context = null;
    private DataSource ds = null;
    private Connection conn = null;

    try {
        context = new InitialContext();
        ds = (DataSource)context.lookup(pool);
        conn = ds.getConnection();           // <--- here is where it hangs 
        
        // use the connection


        if (conn != null)
            conn.close();

        if (context != null)
            context.close();

    } 
    catch (NamingException e) {
        logger.error(e.getMessage());
        throw new DAOException(e.getMessage());
    } 
    catch (SQLException e) {
        logger.error(e.getMessage());
        throw new DAOException(e.getMessage());  // <--- this error is thrown
    }

standalone.xml中的数据源配置

            <datasource jta="true" jndi-name="java:jboss/datasources/IndustryDS" 
                        pool-name="IndustryDS" enabled="true" use-java-context="true">
                <connection-url>jdbc:mariadb://localhost:3306/industry</connection-url>
                <driver>mariadb</driver>
                <security>
                    <user-name>user</user-name>
                    <password>xxxxxx/password>
                </security>
            </datasource>

默认情况下,MariaDB 支持 150 个连接,因此数据库应该不是问题所在。 Wildfly 中默认的最大池大小是 20,我是系统中的唯一用户。每次我在我的应用程序中启动一个功能时,我都会请求两个连接然后断开连接。

为什么数据源连接在我关闭后仍然不可用?

您的代码存在一个问题,如果出现异常,上下文和连接可能不会关闭。

解决此问题的旧方法是关闭 finally 块中的资源。现代方法是使用 try with resources。例如:

try (InitialContext context = new InitialContext();
     Connection conn = ((DataSource) context.lookup(pool)).getConnection()) {
    // use the connection
} catch (NamingException e) {
    logger.error(e.getMessage());
    throw new DAOException(e.getMessage());
} catch (SQLException e) {
    logger.error(e.getMessage());
    throw new DAOException(e.getMessage()); 
}

尝试使用资源 从资源声明开始,其中声明和初始化资源。然后是使用资源的主体。最后你有(可选)catchfinally 块。

秘诀在于 try with resources 构造将自动关闭每个(非空)资源,与打开它们的顺序相反。关闭调用抛出的异常将得到适当处理。等等。

(您可以用 finally 块以旧方式实现(或多或少)相同的事情,但它很复杂。)

我使用 JPA 以非常不同的方式完成了这项工作,并且从未遇到过问题。我的代码看起来像:

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;


public class MyClass {
    @PersistenceContext
    private EntityManager entityManager;

    public SomeObject getSomeObject() {
        // as an example query
        Query query = entityManager.createQuery("select ...")
    }
}

META-INF/persistence.xml 中需要一些额外的配置,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
             http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
             version="2.1">
    <persistence-unit name="somethingPU" transaction-type="JTA">
        <jta-data-source>jdbc/yourJNDIName</jta-data-source>
    </persistence-unit>
</persistence>

通过这种方式,您永远不会处理连接管理 - 容器(在您的情况下为 Wildfly)会为您处理。

这是对我有用的方法。

  1. 在调试模式下启用缓存连接管理器

    <cached-connection-manager debug="true" error="true"/>

  2. 在您的日志文件中查找此文本 - “正在为您关闭连接。请自行关闭它们”。这将帮助您找到代码中的漏洞。

  3. 在我的例子中,jdbcTemplate.getConnection().createClob() 导致池耗尽。

    try {
         Connection conn = jdbcTemplate.getConnection()
         ....
         conn.createClob();
         ...
    } catch() {
      ...
    } finally {
       conn.close()
    }

如上所示正确关闭连接对我们有用。

希望这能为某人节省很多时间。