Тайм-аут клиента .Net - PullRequest
1 голос
/ 12 марта 2012

В моем приложении Windows я пытаюсь подключиться к SQL Server 2008 с помощью следующего кода:

SqlConnection connection = new SqlConnection(Properties.Settings.Default.KargarBandarConnectionString);
SqlCommand command = new SqlCommand("Select IsAdmin from Users where UserName=@UserName And Password=@Password", connection);
SqlDataReader dataReader = null;

command.Parameters.AddWithValue("@UserName", UserNameTextBox.Text.Trim());
command.Parameters.AddWithValue("@Password", PasswordTextBox.Text);
try
{
    connection.Open();
    dataReader = command.ExecuteReader();

    if (dataReader.HasRows)
    {
        while (dataReader.Read())
        {
            IsAdmin = dataReader.GetBoolean(0);
        }
        this.DialogResult = DialogResult.OK;
    }
    else
    {
       FMessageBox.ShowWarning("error");
        UserNameTextBox.Focus();
    }
}
catch (Exception ex)
{
    if (progressForm != null)
        progressForm.Close();

    FMessageBox.ShowError(ex.Message);
}
finally
{
    if (dataReader != null)
    {
        dataReader.Close();
        dataReader.Dispose();
    }
    if (connection != null)
    {
        connection.Close();
        connection.Dispose();
    }
}

Все работает правильно, но иногда я получаю следующую ошибку:

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

Как это можно решить?

Ответы [ 3 ]

3 голосов
/ 12 марта 2012

Причина, по которой вы получаете это исключение, заключается в том, что вы исчерпали пул соединений и количество «доступных» соединений в вашем приложении.

Каждый раз, когда вы открываете соединение, одно соединение извлекается из соединения.пул, если возможно, или новый, если нет.

Однако, чтобы предотвратить скачкообразное использование соединений, существует ограничение в 100 (я думаю, что это настраивается), и если вы попытаетесь использовать более 100при одновременных подключениях код не создаст новые, а вместо этого сядет в ожидании возвращения одного в пул, и в этом случае вы получите тайм-аут, если он слишком длинный.

Итак, для конкретного примера кода, который вы показали, я бы:

Закрыть соединение до Я покажу пользователю сообщения об ошибках

Однако, если 100 пользователей не увидят сообщение об ошибке и не оставят его там одновременно , маловероятно, что код, который вы указали, является причиной этой проблемы.

Кроме этого, я просматриваю все приложение и проверяю, нет ли утечек в других местах.

Этот конкретный тип исключения может возникнуть в одном месте, даже если проблемагде-то ещеПример. В отчете происходит утечка открытого соединения при каждом запуске, и вы запускаете его 100 раз успешно, затем кто-то пытается войти в систему, и в форме входа возникает исключение.

1 голос
/ 12 марта 2012

Это происходит, если вы либо:

  • утечка соединений (оставляя их для GC, а не выбрасывая их)
  • просто слишком много происходит, так что бассейн исчерпан

Первый является наиболее распространенным, и я ожидаю , это во многом связано с тем, что вы чрезмерно усложняете обработку ошибок. Это позволяет легко пропустить, и трудно заметить, что вы пропустили это. Показанный код выглядит хорошо, но было бы гораздо предпочтительнее использовать блоки using для всех элементов IDisposable, а не finally. Также; не сохраняйте соединение, пока вы показываете модальные вещи, такие как окно сообщения, если только не нужно соединение впоследствии. Честно говоря, большую пользу здесь можно получить, если четко разделить пользовательский интерфейс и код доступа к данным, тогда будет , а не искушение , чтобы вставить сообщение в середине запроса к базе данных.

Тем не менее! Если говорить прямо, я считаю, что этот код является жертвой какого-либо другого кода, который блокирует соединения. Посмотрите на ваш другой код доступа к данным для причины этого.

0 голосов
/ 12 марта 2012

Сделайте так, чтобы ваш код выглядел примерно так. Реализуйте using блоков. Другие ответы здесь очень важны, обязательно поймите их.

bool res=false;
try
{
    using(var connection = new SqlConnection(Properties.Settings.Default.KargarBandarConnectionString))
    using(var cmd = conn.CreateCommand())
    {       
        cmd.commandText = "Select IsAdmin from Users where UserName=@UserName And HashedAndSaltedPassword=@PwdHash";
        cmd.Parameters.AddWithValue("@UserName", UserNameTextBox.Text.Trim());
        cmd.Parameters.AddWithValue("@PwdHash", SaltAndHash(PasswordTextBox.Text));     
        connection.Open();
        var result = cmd.ExecuteScalar();
        if (result!=null)
        {
            res=bool.Parse(result);       
            this.DialogResult = DialogResult.OK;
        }   
    }
}
catch (Exception ex)
{   
    if (progressForm != null){progressForm.Close();}
    FMessageBox.ShowError(ex.Message);
}

if(res==false)
{
    FMessageBox.ShowWarning("error");
    UserNameTextBox.Focus();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...