Question

Yat-il un moyen de vérifier les fuites de connexion dans une application Java EE?

L'application est en cours d'exécution sur ma machine locale. Il utilise une base de données MySQL et un utilisateur entre ses informations dans cette base de données.

Dans mes moyens de fuite de connexion d'opinion ne pas fermer l'objet de connexion correctement. Je crée trop de connexions de base de données dans mon application. Je veux vérifier s'il y a une fuite de connexion dans les connexions de base de données.

Était-ce utile?

La solution

log4jdbc , un pilote Java JDBC qui peut se connecter SQL et / ou appels JDBC pour d'autres pilotes JDBC, a un enregistreur qui enregistre des événements ouvrir et fermer connexion ainsi que le dumping tous les numéros de connexion ouverts. Ceci est très utile pour traquer les problèmes de fuite de connexion .

Un autre outil que vous pouvez vérifier est ConnLeakFinder , un outil simple à mettre le doigt sur la connexion jdbc fuites dans le code java . Je n'ai aucune expérience avec cependant.

Autres conseils

Si vous utilisez un serveur d'application Java EE, vous devriez être en mesure de le configurer pour vérifier les connexions quand ils sortent et récupèrent les connexions obsolètes quand ils ne reviennent pas.

fuite de connexion est en effet un problème. Je serais inquiet si vous aviez la gestion des connexions dispersés dans tant d'endroits dans le code qu'il était un gros problème pour les trouver. J'espère voir un pool de connexion Java EE qui a été utilisé que dans une couche de persistance bien définie. Les connexions doivent être ouvertes par une couche de service qui gère la transaction pour cette unité de travail et le ferme dès que le cas d'utilisation est terminée, dans la portée de la méthode dans un bloc finally.

Si ce n'est pas vrai, je pense qu'il est temps de refactoring.

essayez d'utiliser FindBug . Il est un outil d'analyse de code statique et disponible en tant que plug-in Eclipse ainsi que l'application autonome. En dehors de la connexion leackage il trouvera d'autres problèmes dans votre application aussi

Utiliser une usine de connexion, par exemple:

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

De cette façon, vous ne laissez jamais sans surveillance derrière les connexions. Utilisez un pool de connexion si vous avez besoin de plus d'une connexion (pour la performance). La plupart des appservers ont une installation de pool de connexion JDBC.

La meilleure façon de lutter contre les fuites de connexion est de faire pendant le test .

Vous pouvez utiliser un utilitaire automatisé afin que chaque vérifie d'essai s'il y a une fuite de connexion.

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

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

Les regards ConnectionLeakUtil comme ceci:

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

Les implémentations IdleConnectionCounter se trouvent dans ce blog , et la version MySQL comme ceci:

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

Maintenant, lorsque vous exécutez vos tests, vous aurez un échec lorsqu'une connexion est une fuite.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top