Подтвердить что ты не робот

SqlCommand.Dispose() перед SqlTransaction.Commit()?

будет ли он работать для распоряжения командой, назначенной транзакции до совершения транзакции? Я сам тестировал следующий код, и, похоже, он работал нормально, но это довольно небольшой пример, поэтому я ищу подтверждение, если кто-то положительно знает.

internal static void TestTransaction()
{
    try
    {
        Program.dbConnection.Open();
        using (SqlTransaction transaction = Program.dbConnection.BeginTransaction())
        {
            Boolean doRollback = false;
            for (int i = 0; i < 10; i++)
            {
                using (SqlCommand cmd = new SqlCommand("INSERT INTO [testdb].[dbo].[transactiontest] (testvalcol) VALUES (@index)", Program.dbConnection, transaction))
                {
                    cmd.Parameters.AddWithValue("@index", i);
                    try
                    {
                        cmd.ExecuteNonQuery();
                    }
                    catch (SqlException)
                    {
                        doRollback = true;
                        break;
                    }
                }
            }
            if (doRollback)
                transaction.Rollback();
            else
                transaction.Commit();
        }
    }
    finally
    {
        Program.dbConnection.Close();
    }
}
4b9b3361

Ответ 1

Объекты соединения, транзакции и команды - это просто транспортные средства для отправки команд в базу данных. После выполнения команды база данных ее получила. Независимо от того, что вы делаете с объектом команды впоследствии, уничтожайте его, сжигайте или стреляйте в луну, этот факт не меняется. (Его можно отбросить только назад).

Вы можете создавать и удалять столько команд, сколько хотите, в пределах одного SqlConnection (с или без SqlTransaction). И вы можете запускать и размещать столько транзакций, сколько хотите, за один SqlConnection. Чтобы продемонстрировать это, см.:

using (var conn = new SqlConnection(@"server=(local)\sql2008;database=Junk;Integrated Security=SSPI"))
{
  conn.Open();
  // Repeat this block as often as you like...
  using (var tran = conn.BeginTransaction())
  {
    using (var cmd = new SqlCommand("INSERT INTO Mess VALUES ('mess1')", conn, tran))
    {
      cmd.ExecuteNonQuery(); // Shows in Sql profiler
    }
    tran.Commit(); // Commits
  }
  using (var cmd = new SqlCommand("INSERT INTO Mess VALUES ('mess2')", conn))
  {
    cmd.ExecuteNonQuery(); // Executes and commits (implicit transaction).
  }
}

Конечно, для здорового кода вам нужно распоряжаться всеми объектами в правильном порядке. Устранение команды после удаления SqlConnection может привести к тому, что объект соединения останется в памяти.

Ответ 2

Да, это, вероятно, безопасно. using() закрывает команду, а не соединение.

Но вы должны поместить это соединение в другой блок using() или в конструкцию try/finally.

Ответ 3

Подтверждено, это работает очень хорошо и (по крайней мере, здесь, в нашей компании) даже считается правильным.

  • создать соединение
  • создать транзакцию
  • создать команду (ы), использовать транзакцию, выполнить
  • удалить команду (ы)
  • совершить транзакцию
  • удалять соединение