Многопользовательское подключение и одновременное выполнение CRUD

#c# #asp.net #sql #sql-server-2008 #iis-7

#c# #asp.net #sql #sql-server-2008 #iis-7

Вопрос:

Я использую ASP.NET Framework 4, IIS 7 и SQL Server 2008 R2.

Я получил ошибку типа: {column} not found in selected DataSource,
SQL Reader is close
, ….

Это происходит только тогда, когда:

  1. Подключено несколько пользователей.
  2. Они выполняют вызовы CRUD (создание, повторный поиск, обновление, удаление) одновременно.

Как ни странно, это ускользает от моего улова:

 try{
    Connexion_D.GetConnected();
    // doing CRUD
}
catch{
    // catching Error, avoid yellow page aspx
}
finally
{
    Connexion_D.CloseConnection();
} 
  

И мой класс подключения:

 public class Connexion_D
{

    static public SqlConnection conn;
    static public SqlConnection GetConnected()
    {
        try
        {
            String strConnectionString = ConfigurationManager.ConnectionStrings["xxxxx"].ConnectionString;
            conn = new SqlConnection(strConnectionString);
        }
        catch (Exception excThrown)
        {
            conn = null;
            throw new Exception(excThrown.InnerException.Message, excThrown);
        }

        // Ouverture et restitution de la connexion en cours
        if (conn.State == ConnectionState.Closed) conn.Open();
        return conn;
    }
    static public Boolean IsConnected
    {
        get { return (conn != null) amp;amp; (conn.State != ConnectionState.Closed) amp;amp; (conn.State != ConnectionState.Broken); }
    }

    static public void CloseConnection()
    {
        // Libération de la connexion si elle existe
        if (IsConnected) conn.Close();
    }
}
  

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

Я думаю, что это может быть конфигурация IIS и SQL server.

Есть идеи?

Заранее благодарю.

Комментарии:

1. Пожалуйста, укажите полную информацию об ошибке и пример кода, который продемонстрирует ошибку, т.Е. достаточно информации для повторного создания. Также читайте tinyurl.com/so-hints для получения дополнительных советов о том, как сделать этот вопрос ответственным.

2. В выбранном источнике данных не найдено поле или свойство с именем ‘XXX’. но, как я уже сказал, это происходит только при многопользовательском использовании, потому что я проверил, что этот xxx существует, и у меня нет проблем, когда я подключаюсь один.

3. Для ExecuteReader требуется открытое и доступное соединение. В данный момент соединение закрыто.

Ответ №1:

Если я правильно понимаю, что вы делаете, то это выглядит очень сомнительно:

 static public SqlConnection conn;     
static public SqlConnection GetConnected() {         
    try         
    {             
        String strConnectionString = ConfigurationManager.ConnectionStrings["xxxxx"].ConnectionString;             
        conn = new SqlConnection(strConnectionString);
    } 
}

static public void CloseConnection() {           
    // Libération de la connexion si elle existe           
    if (IsConnected) conn.Close();       
}   
  

Вы работаете со статической переменной соединения, что означает, что когда вы закрываете ее, вы закрываете последнюю, которая была открыта.

В многопользовательском сценарии это может произойти:

  • Пользователь A: Создайте соединение (и верните соединение 1)
  • Пользователь A: Выполнить запрос (выполняется с подключением 1)
  • Пользователь B: Создайте соединение (и верните соединение 2)
  • Пользователь A: Закрыть соединение (последним открытым было 2, так что оно закрыто)
  • Пользователь B: Выполнить запрос (выполняется для подключения 2, оно уже закрыто … взрыв)

Кроме того, вам, вероятно, следует пересмотреть использование вашего соединения в качестве общедоступной переменной-члена:

 static public SqlConnection conn;     
  

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

Редактировать:

Казалось бы, наиболее очевидным решением было бы прекратить статическое соединение. Тогда ваш клиентский код мог бы выглядеть примерно так:

 try{
    // use using block around connection, calls dispose automatically when
    // block ends...
    using(var connectionWrapper = new Connexion_D()) {
        var connectedConnection = connectionWrapper.GetConnected();        
        // do CRUD
    }
}
catch{
    // catching Error, avoid yellow page aspx
    // Really you should probably be doing something with the exception (logging?)
    // particularly since you go to the effort of throwing it from your Connection_D
    // class.
}
  

Код вашего класса выглядит как:

 /* Implement IDisposable to cleanup connection */
public class Connexion_D : IDisposable 
{
    public SqlConnection conn;

    public SqlConnection GetConnected()
    {
        try
        {
            String strConnectionString = ConfigurationManager.ConnectionStrings["xxxxx"].ConnectionString;
            conn = new SqlConnection(strConnectionString);
        }
        catch (Exception excThrown)
        {
            conn = null;
            throw new Exception(excThrown.InnerException.Message, excThrown);
        }

        // Ouverture et restitution de la connexion en cours
        if (conn.State == ConnectionState.Closed) conn.Open();
        return conn;
    }
    public Boolean IsConnected
    {
        get { return (conn != null) amp;amp; (conn.State != ConnectionState.Closed) amp;amp; (conn.State != ConnectionState.Broken); }
    }

    public void CloseConnection()
    {
        // Libération de la connexion si elle existe
        if (IsConnected) { 
            conn.Close();
            conn = null;
        }
    }

    // Implement IDisposable.
    // Do not make this method virtual.
    // A derived class should not be able to override this method.
    public void Dispose()
    {
        // Close connection
    }
}
  

Смотрите это для получения дополнительной информации о реализации IDisposable.

Комментарии:

1. Спасибо за ваш ответ, можете ли вы внести предложение? должен ли я использовать одноэлементный шаблон?

2. @user609511: Я обновил свой ответ с помощью подхода . Singleton может работать, но вам придется совместно использовать соединение между несколькими пользователями, что может вызвать проблемы при обновлении транзакций / повторном подключении и т.д. Я думаю, вам лучше иметь несколько подключений для поддержания изоляции. Возможно, вы захотите взглянуть на пул соединений, если в конечном итоге у вас возникнут проблемы с производительностью, но я бы побеспокоился об этом, если вы туда доберетесь.