8

接続リークがあると思われるアプリがあります (SQL Server は、最大プール サイズに達したと言っています)。私は自分の開発マシンで (明らかに) 一人で、アプリをナビゲートするだけで、このエラーをトリガーします。SQL Server アクティビティ モニターに、データベースを使用している多数のプロセスが表示されます。

接続を開いているが使用していないファイルを見つけたい。grep のようなものを使用して、ファイルごとに「.Open()」の数と「.Close()」の数を数え、それらの数が等しくないファイルを取得することを考えていました。それは現実的ですか?

おまけの質問: SQL Server アクティビティ モニターで見つかったプロセスは、接続に対応していますか? そうでない場合、データベースで開いている接続の数を確認するにはどうすればよいですか?

アプリは、SQL Server 2005 を使用する asp.net (vb) 3.5 にあります。現在、LINQ (まだ) などは使用していません。

ありがとう

4

2 に答える 2

10

SQL Server 側からコードを見ると、次のクエリを実行して、スリープ状態の接続で最後に実行されたクエリに関するビューを取得できます。(何もしていない接続を開く)

SELECT ec.session_id, last_read, last_write, text, client_net_address, program_name, host_process_id, login_name
FROM sys.dm_exec_connections  ec
JOIN sys.dm_exec_sessions es
  ON ec.session_id = es.session_id
CROSS APPLY sys.dm_exec_sql_text(ec.most_recent_sql_handle) AS dest
where es.status = 'sleeping'

アプリケーション側からは、次の記事で説明されているように、sos.dll を使用してデバッグできます。

windbg の使用方法に関する詳細情報が必要な場合は、次の記事が参考になります。

于 2011-04-21T11:23:41.407 に答える
6

接続リークに取り組む最善の方法は、テスト中に行うことです。

自動ユーティリティを使用して、各テストで接続リークがあるかどうかを確認できます。

@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[ブログ投稿][1] で見つけることができ、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 );
        }
    }
}

ここで、テストを実行すると、接続がリークしているときにエラーが発生します。

:hibernate-core:test
 
org.hibernate.jpa.test.EntityManagerFactoryClosedTest > classMethod FAILED
    org.hibernate.testing.jdbc.leak.ConnectionLeakException
于 2016-07-12T13:10:58.437 に答える