Как проверить утечку соединения с базой данных в приложении Java EE? - PullRequest
5 голосов
/ 19 июня 2010

Есть ли способ проверить утечку соединения в приложении Java EE?

Приложение работает на моей локальной машине. Он использует базу данных MySQL, и пользователь вводит свои данные в эту базу данных.

По моему мнению, утечка соединения означает неправильное закрытие объекта соединения. Я создаю слишком много соединений с базой данных в моем приложении. Я хочу проверить, есть ли утечка соединений в соединениях с базой данных.

Ответы [ 5 ]

12 голосов
/ 19 июня 2010

log4jdbc , драйвер JDBC Java, который может регистрировать вызовы SQL и / или JDBC для других драйверов JDBC, имеет регистратор, который регистрирует события открытия и закрытия соединения, а также выводит все номера открытых соединений,Это очень полезно для поиска проблем утечки соединения .

Еще одним инструментом, который вы можете проверить, является ConnLeakFinder , простой инструмент для определения утечек jdbc-соединения в коде java .У меня нет никакого опыта с этим, хотя.

1 голос
/ 19 июня 2010

Если вы используете сервер приложений Java EE, вы сможете настроить его так, чтобы он проверял соединения, когда они выходили, и восстанавливал устаревшие соединения, когда они не возвращались.

Утечка соединения действительно является проблемой. Я был бы обеспокоен, если бы у вас было настолько разбросано управление соединением во многих местах кода, что найти их все было большой проблемой. Я ожидаю увидеть пул соединений Java EE, который использовался только в пределах четко определенного уровня персистентности. Соединения должны открываться сервисным уровнем, который управляет транзакцией для этой единицы работы и закрывает ее, как только закончится сценарий использования, в рамках метода в блоке finally.

Если это не так, думаю, пришло время провести рефакторинг.

0 голосов
/ 12 июля 2016

Лучший способ устранить утечки в соединении - это сделать во время тестирования .

Вы можете использовать автоматизированную утилиту, чтобы каждый тест проверял наличие утечки соединения.

@BeforeClass
public static void initConnectionLeakUtility() {
    if ( enableConnectionLeakDetection ) {
        connectionLeakUtil = new ConnectionLeakUtil();
    }
}

@AfterClass
public static void assertNoLeaks() {
    if ( enableConnectionLeakDetection ) {
        connectionLeakUtil.assertNoLeaks();
    }
}

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

Реализации 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 );
        }
    }
}

Теперь, когда вы запустите свои тесты, вы получите ошибку, когдапроисходит утечка соединения.

0 голосов
/ 19 июня 2010

Используйте фабрику соединений, например:

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

Таким образом, вы никогда не оставите без присмотра соединения.Используйте пул соединений, если вам нужно более одного соединения (для производительности).Большинство серверов приложений имеют функцию пула соединений JDBC.

0 голосов
/ 19 июня 2010

попробуйте использовать FindBug . Это инструмент для статического анализа кода, доступный как плагин eclipse, а также как отдельное приложение. Помимо утечки соединения он найдет и другие проблемы в вашем приложении

...