1

When working on a project which uses a lot of database connections, I've been encountering a number of errors relating to timeouts when acquiring a connection from the pool using MSSQL.

As a matter of course, all the DB connectivity is in using blocks, so any connections should be cleared down properly when they are closed, however one persistent error comes up in a using block where a single line is read in a reader object, then a break statement is hit, as shown below.

using (SqlConnection connection = new SqlConnection(connectionString)) {
    connection.Open();
    using (SqlCommand command = new SqlCommand(sqlString, connection)) {

        using (SqlDataReader reader = command.ExecuteReader()) {
            while (reader.Read()) {
                //Do something with the data then break
                break;
            }
        }
    }
}

The error is intermittent, but occurs on 4 out of every 5 test sessions I run on the system. I realise that leaving the using block should cause the connection to close cleanly and release it to the pool for reuse, however it is curious that this error comes up consistently in this one area.

After changing the read to remove the while and the break, I have not seen this issue occur again

using (SqlConnection connection = new SqlConnection(connectionString)) {
    connection.Open();
    using (SqlCommand command = new SqlCommand(sqlString, connection)) {

        using (SqlDataReader reader = command.ExecuteReader()) {
            if (reader.Read()) {
                //Do something with the data 
                //No need to break, as the select uses a unique ID for the row
            }
        }
    }
}

In order to further debug this issue, I need to work out which avenues to explore, and if the system failing to acquire a connection from the pool within the timeout period is simply a coincidence arising from the sheer number of DB connections, I will need to refactor several methods to change the behaviour.

Is the mechanism which causes the DB connection to be returned to the pool triggered by the using block exiting cleanly (i.e. running to the end brace), or by the scope changing?

Alex
  • 1,643
  • 1
  • 14
  • 32

1 Answers1

2

The break is doing nothing more than terminating the while loop; it does not and cannot have an effect on the enclosing using. In both cases the connection will be closed and returned to the pool.

However, it is entirely possible that the code with the while loop is causing the problem: if it was selecting a million results, and looping through all of them to find the single row with the ID it was interested in, then that would definitely tie up a connection unnecessarily.

Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
  • It only read a single row as the select was using a unique column to identify the row. The only other change to the code than listed above was that in the original version, the columns were read using their number and a ternary comparison returned either the value or a default, depending on whether they were `DBNull`. Now, I read the object, compare to `DBNull.Value` and cast if it's not null. – Alex Feb 02 '19 at 13:10
  • So the content of `sqlString` has not changed between these two pieces of code, only the code inside the `using`? Either way, the fact that you *have* changed the reading code between the two versions does suggest it, and not the `while/if`, was the problem. – Ian Kemp Feb 02 '19 at 13:42
  • The problem is still there, it was just chance that it didn't come up again. It seems that the sheer number of connections the code is acquiring is causing the issue, and needs to be refactored in some way to reduce the hit on the database. – Alex Feb 04 '19 at 13:49
  • 1
    The issue turns out to stem from frequency that connections are dropped and recreated. There is an issue with connections not being returned to the pool properly, so I have to periodically clear the pool manually. – Alex Feb 08 '19 at 12:22