5

我们有一个似乎有连接泄漏的应用程序(SQL Server说已达到最大池大小)。我一个人在我的开发机器上(显然),只是通过浏览应用程序,我触发了这个错误。 SQL Server活动监视器显示使用我的数据库的大量进程。跟踪连接泄漏

我想找到哪些文件打开连接但不使用它。我正在考虑对每个文件使用类似grep的内容来计算“.Open()”的数量和“.Close()”的数量,并获取数字不相等的文件。这是现实吗?

奖金问题:在SQL Server活动监视器中找到的进程是否对应于连接?如果不是,我怎么知道我的数据库上有多少连接是打开的?

该应用程序在asp.net(vb)3.5,SQL Server 2005中。我们目前不使用linq(或)或类似的东西。

感谢

+0

你的应用程序以什么语言编码? – 2011-04-21 09:03:03

+0

Asp.net。为了反映这一点,我编辑了原始问题。 – thomasb 2011-04-21 10:19:27

回答

9

当从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的信息,这些文章是一个很好的介绍:

+0

谢谢,但你的第2部分链接与第1部分相同。第2部分在这里:http://blogs.msdn.com/b/psssql/archive/2009/02/10/how-to-troubleshoot-leaked- sqlconnection-objects-net-2-0-part-2.aspx – thomasb 2011-04-21 13:33:56

+0

我觉得我不明白这些文章中的任何内容。我甚至不知道在哪里输入命令。 – thomasb 2011-04-21 13:40:46

+0

对不起,修复了第二部分的链接。这篇文章是关于使用windbg.exe和sos.dll来调试你的应用程序。 – 2011-04-21 14:04:57

1

tackle connection leaks is to do it during testing的最佳方式。

您可以使用自动化实用程序,以便每个测试都会验证是否存在连接泄漏。

@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实现可以在这个blog post发现,和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