如何检查 Java EE 应用程序中的数据库连接泄漏?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3075501/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to check the Database Connection leakage in Java EE application?
提问by User 1034
Is there any way to check the connection leakage in a Java EE application?
有没有办法检查 Java EE 应用程序中的连接泄漏?
The application is running on my local machine. It uses a MySQL database and a user enters his details into this database.
该应用程序正在我的本地机器上运行。它使用 MySQL 数据库,用户将其详细信息输入该数据库。
In my opinion connection leakage means not closing the connection object properly. I am creating too many database connections in my application. I want to check if there is any connection leakage in the database connections.
在我看来,连接泄漏意味着没有正确关闭连接对象。我在我的应用程序中创建了太多的数据库连接。我想检查数据库连接中是否有任何连接泄漏。
采纳答案by Pascal Thivent
log4jdbc, a Java JDBC driver that can log SQL and/or JDBC calls for other JDBC drivers, has a logger which logs connection open and close events as well as dumping all open connection numbers. This is very useful for hunting down connection leak problems.
log4jdbc是一个 Java JDBC 驱动程序,可以记录其他 JDBC 驱动程序的 SQL 和/或 JDBC 调用,它有一个记录器,可以记录连接打开和关闭事件以及转储所有打开的连接号。这对于查找连接泄漏问题非常有用。
Another tool that you might want to check is ConnLeakFinder, a simple tool to pinpoint jdbc connection leaks in java code. I don't have any experience with it though.
您可能想要检查的另一个工具是ConnLeakFinder,这是一个用于在 Java 代码中查明 jdbc 连接泄漏的简单工具。虽然我没有任何经验。
回答by Vinay Lodha
回答by duffymo
If you're using a Java EE app server, you should be able to configure it to check connections when they go out and reclaim stale connections when they don't come back.
如果您使用的是 Java EE 应用服务器,您应该能够将其配置为在它们出去时检查连接并在它们不回来时回收过时的连接。
Connection leakage is indeed a problem. I'd be worried if you had connection management scattered in so many places in the code that it was a big problem to find them all. I'd expect to see a Java EE connection pool that was used only within a well-defined persistence layer. Connections should be opened by a service layer that manages the transaction for that unit of work and closes it as soon as the use case is over, within method scope in a finally block.
连接泄漏确实是一个问题。如果连接管理分散在代码中的很多地方,找到所有这些地方是个大问题,我会很担心。我希望看到一个仅在明确定义的持久层中使用的 Java EE 连接池。连接应该由管理该工作单元的事务的服务层打开,并在用例结束后立即关闭它,在 finally 块的方法范围内。
If that's not true, I think it's time to refactor.
如果这不是真的,我认为是时候重构了。
回答by Patrick Holthuizen
Use a connection factory, for example:
使用连接工厂,例如:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectionFactory {
private static Connection connection;
public static synchronized Connection getConnection() throws SQLException {
if (connection == null || connection.isClosed()) {
connection = DriverManager.getConnection("url");
}
return connection;
}
}
This way you never leave unattended connections behind. Use a connection pool if you need more than one connection (for performance). Most appservers have a JDBC connection pool facility.
这样您就永远不会留下无人值守的连接。如果您需要多个连接(为了性能),请使用连接池。大多数应用程序服务器都有一个 JDBC 连接池工具。
回答by Vlad Mihalcea
The best way to tackle connection leaks is to do it during testing.
You can use an automated utility so that each test verifies if there is a connection leak.
您可以使用自动化实用程序,以便每个测试都验证是否存在连接泄漏。
@BeforeClass
public static void initConnectionLeakUtility() {
if ( enableConnectionLeakDetection ) {
connectionLeakUtil = new ConnectionLeakUtil();
}
}
@AfterClass
public static void assertNoLeaks() {
if ( enableConnectionLeakDetection ) {
connectionLeakUtil.assertNoLeaks();
}
}
The ConnectionLeakUtil
looks like this:
该ConnectionLeakUtil
如下所示:
public class ConnectionLeakUtil {
private JdbcProperties jdbcProperties = JdbcProperties.INSTANCE;
private List idleConnectionCounters =
Arrays.asList(
H2IdleConnectionCounter.INSTANCE,
OracleIdleConnectionCounter.INSTANCE,
PostgreSQLIdleConnectionCounter.INSTANCE,
MySQLIdleConnectionCounter.INSTANCE
);
private IdleConnectionCounter connectionCounter;
private int connectionLeakCount;
public ConnectionLeakUtil() {
for ( IdleConnectionCounter connectionCounter :
idleConnectionCounters ) {
if ( connectionCounter.appliesTo(
Dialect.getDialect().getClass() ) ) {
this.connectionCounter = connectionCounter;
break;
}
}
if ( connectionCounter != null ) {
connectionLeakCount = countConnectionLeaks();
}
}
public void assertNoLeaks() {
if ( connectionCounter != null ) {
int currentConnectionLeakCount = countConnectionLeaks();
int diff = currentConnectionLeakCount - connectionLeakCount;
if ( diff > 0 ) {
throw new ConnectionLeakException(
String.format(
"%d connection(s) have been leaked! Previous leak count: %d, Current leak count: %d",
diff,
connectionLeakCount,
currentConnectionLeakCount
)
);
}
}
}
private int countConnectionLeaks() {
try ( Connection connection = newConnection() ) {
return connectionCounter.count( connection );
}
catch ( SQLException e ) {
throw new IllegalStateException( e );
}
}
private Connection newConnection() {
try {
return DriverManager.getConnection(
jdbcProperties.getUrl(),
jdbcProperties.getUser(),
jdbcProperties.getPassword()
);
}
catch ( SQLException e ) {
throw new IllegalStateException( e );
}
}
}
The IdleConnectionCounter
implementations can be found in this blog post, and the MySQL version like this:
该IdleConnectionCounter
实现可以在本作中找到的博客文章,和MySQL的版本是这样的:
public class MySQLIdleConnectionCounter implements IdleConnectionCounter {
public static final IdleConnectionCounter INSTANCE =
new MySQLIdleConnectionCounter();
@Override
public boolean appliesTo(Class<? extends Dialect> dialect) {
return MySQL5Dialect.class.isAssignableFrom( dialect );
}
@Override
public int count(Connection connection) {
try ( Statement statement = connection.createStatement() ) {
try ( ResultSet resultSet = statement.executeQuery(
"SHOW PROCESSLIST" ) ) {
int count = 0;
while ( resultSet.next() ) {
String state = resultSet.getString( "command" );
if ( "sleep".equalsIgnoreCase( state ) ) {
count++;
}
}
return count;
}
}
catch ( SQLException e ) {
throw new IllegalStateException( e );
}
}
}
Now, when you run your tests, you'll get a failure when a connection is being leaked.
现在,当您运行测试时,会在连接泄漏时遇到故障。