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());
}
尝试使用资源 从资源声明开始,其中声明和初始化资源。然后是使用资源的主体。最后你有(可选)catch
和 finally
块。
秘诀在于 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)会为您处理。
这是对我有用的方法。
在调试模式下启用缓存连接管理器
<cached-connection-manager debug="true" error="true"/>
在您的日志文件中查找此文本 - “正在为您关闭连接。请自行关闭它们”。这将帮助您找到代码中的漏洞。
在我的例子中,jdbcTemplate.getConnection().createClob()
导致池耗尽。
try {
Connection conn = jdbcTemplate.getConnection()
....
conn.createClob();
...
} catch() {
...
} finally {
conn.close()
}
如上所示正确关闭连接对我们有用。
希望这能为某人节省很多时间。
我有一个 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());
}
尝试使用资源 从资源声明开始,其中声明和初始化资源。然后是使用资源的主体。最后你有(可选)catch
和 finally
块。
秘诀在于 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)会为您处理。
这是对我有用的方法。
在调试模式下启用缓存连接管理器
<cached-connection-manager debug="true" error="true"/>
在您的日志文件中查找此文本 - “正在为您关闭连接。请自行关闭它们”。这将帮助您找到代码中的漏洞。
在我的例子中,
jdbcTemplate.getConnection().createClob()
导致池耗尽。
try {
Connection conn = jdbcTemplate.getConnection()
....
conn.createClob();
...
} catch() {
...
} finally {
conn.close()
}
如上所示正确关闭连接对我们有用。
希望这能为某人节省很多时间。