Как использовать sqltransaction в C#

Я использую следующий код для выполнения двух команд одновременно. Я использовал sqltransaction, чтобы гарантировать выполнение или откат всех команд. Когда я запускаю свою программу без "транзакции", она запускается правильно, но когда я использую "транзакцию" с ними, они показывают ошибку. Мой код выглядит следующим образом;

SqlTransaction transaction = connectionsql.BeginTransaction();

try
{
    SqlCommand cmd1 = new SqlCommand("select account_name from master_account where NOT account_name = 'BANK' AND NOT account_name = 'LOAN'", connectionsql);
    SqlDataReader dr1 = cmd1.ExecuteReader();
    while (dr1.Read())
    {
        comboBox1.Items.Add(dr1[0].ToString().Trim());
    }
    cmd1.Dispose();
    dr1.Dispose();

    SqlCommand cmd2 = new SqlCommand("select items from rate",connectionsql);
    SqlDataReader dr2 = cmd2.ExecuteReader();
    while (dr2.Read())
    {
        comboBox2.Items.Add(dr2[0].ToString().Trim());
    }
    cmd2.Dispose();
    dr2.Dispose();
    transaction.Commit();

    dateTimePicker4.Value = dateTimePicker3.Value;
}
catch(Exception ex)
{
    transaction.Rollback();
    MessageBox.Show(ex.ToString());
}

и ошибка:

6 ответов

Вы должны указать своим объектам SQLCommand использовать транзакцию:

cmd1.Transaction = transaction;

или в конструкторе:

SqlCommand cmd1 = new SqlCommand("select...", connectionsql, transaction);

Убедитесь, что у вас также открыт объект connectionsql.

Но все, что вы делаете, это операторы SELECT. Транзакции выиграют больше, если вы используете действия типа INSERT, UPDATE и т. Д.

В следующем примере создаются SqlConnection и SqlTransaction. Здесь также показано, как использовать методы BeginTransaction, Commit и Rollback. Транзакция откатывается при любой ошибке или если она удаляется без предварительной фиксации. Обработка ошибок Try/Catch используется для обработки любых ошибок при попытке зафиксировать или откатить транзакцию.

private static void ExecuteSqlTransaction(string connectionString)
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();

        SqlCommand command = connection.CreateCommand();
        SqlTransaction transaction;

        // Start a local transaction.
        transaction = connection.BeginTransaction("SampleTransaction");

        // Must assign both transaction object and connection 
        // to Command object for a pending local transaction
        command.Connection = connection;
        command.Transaction = transaction;

        try
        {
            command.CommandText =
                "Insert into Region (RegionID, RegionDescription) VALUES (100, 'Description')";
            command.ExecuteNonQuery();
            command.CommandText =
                "Insert into Region (RegionID, RegionDescription) VALUES (101, 'Description')";
            command.ExecuteNonQuery();

            // Attempt to commit the transaction.
            transaction.Commit();
            Console.WriteLine("Both records are written to database.");
        }
        catch (Exception ex)
        {
            Console.WriteLine("Commit Exception Type: {0}", ex.GetType());
            Console.WriteLine("  Message: {0}", ex.Message);

            // Attempt to roll back the transaction. 
            try
            {
                transaction.Rollback();
            }
            catch (Exception ex2)
            {
                // This catch block will handle any errors that may have occurred 
                // on the server that would cause the rollback to fail, such as 
                // a closed connection.
                Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
                Console.WriteLine("  Message: {0}", ex2.Message);
            }
        }
    }
}

Смотрите класс SqlTransaction

Вы можете создать SqlTransaction из SqlConnection,

И использовать его для создания любого числа SqlCommands

SqlTransaction transaction = connection.BeginTransaction();
var cmd1 = new SqlCommand(command1Text, connection, transaction);
var cmd2 = new SqlCommand(command2Text, connection, transaction);

Или же

var cmd1 = new SqlCommand(command1Text, connection, connection.BeginTransaction());
var cmd2 = new SqlCommand(command2Text, connection, cmd1.Transaction);

Если сбой команд никогда не вызывает неожиданных изменений , не используйте транзакцию.

если сбой команд может привести к неожиданным изменениям, поместите их в блок Try/Catch и откатите операцию в другом блоке Try/Catch.

По данным MSDN:

Обработка исключенийTry/Catch всегда должна использоваться при откате транзакции. Откат генерирует InvalidOperationException если соединение разорвано или транзакция уже откатана на сервере.

Вот пример кода:

string connStr = "[connection string]";
string cmdTxt = "[t-sql command text]";

using (var conn = new SqlConnection(connStr))
{
    conn.Open();
    var cmd = new SqlCommand(cmdTxt, conn, conn.BeginTransaction());


    try
    {
        cmd.ExecuteNonQuery();
        //before this line, nothing has happened yet
        cmd.Transaction.Commit();
    }
    catch(System.Exception ex)
    {
        //You should always use a Try/Catch for transaction's rollback
        try
        {
            cmd.Transaction.Rollback();
        }
        catch(System.Exception ex2)
        {
            throw ex2;
        }
        throw ex;
    }

    conn.Close();
}

Транзакция откатывается в том случае, если она удаляется до вызова Commit или Rollback.

Так что вам не нужно беспокоиться о закрытии приложения.

Ну, я не понимаю, почему вы использовали транзакцию в случае, когда вы делаете select,

Транзакция полезна при внесении изменений (добавление, редактирование или удаление) данных из базы данных.

Удалить транзакцию, если вы не используете insert, update или же delete заявления

Обновить или удалить с помощью транзакции SQL

 private void SQLTransaction() {
   try {
     string sConnectionString = "My Connection String";
     string query = "UPDATE [dbo].[MyTable] SET ColumnName = '{0}' WHERE ID = {1}";

     SqlConnection connection = new SqlConnection(sConnectionString);
     SqlCommand command = connection.CreateCommand();
     connection.Open();
     SqlTransaction transaction = connection.BeginTransaction("");
     command.Transaction = transaction;
     try {
       foreach(DataRow row in dt_MyData.Rows) {
         command.CommandText = string.Format(query, row["ColumnName"].ToString(), row["ID"].ToString());
         command.ExecuteNonQuery();
       }
       transaction.Commit();
     } catch (Exception ex) {
       transaction.Rollback();
       MessageBox.Show(ex.Message, "Error");
     }
   } catch (Exception ex) {
     MessageBox.Show("Problem connect to database.", "Error");
   }
 }

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

sqlCommand.Transaction = transaction;

А также просто используйте один SqlCommand, не объявляйте более одного, так как переменные занимают место, и мы также находимся в теме повышения эффективности вашего кода, сделаем это, назначив commandText другой строке запроса и выполнив их следующим образом:

sqlCommand.CommandText = "select * from table1";
sqlCommand.ExecuteNonQuery();
sqlCommand.CommandText = "select * from table2";
sqlCommand.ExecuteNonQuery();
Другие вопросы по тегам