C#. ADO .NET. Клас DbTransaction. Використання транзакцій

Приєднаний режим (connected mode). Клас DbTransaction. Використання транзакцій

Перед вивченням даної теми рекомендується ознайомитись з наступними темами:

 

1. Клас DbTransaction. Загальні відомості

Якщо при роботі з базами даних використовуються транзакції, то технологія ADO .NET дає в розпорядження програміста ряд засобів (класів, зчислень) основним з яких є клас DbTransaction.

Клас DbTransaction використовується, якщо в команді SQL, яка змінює дані, потрібно зафіксувати або відмінити транзакцію. Як відомо, зміни в даних вносять команди типу:

  • INSERT – вставка нового рядка в базу даних;
  • UPDATE – оновлення рядка;
  • DELETE – видалення рядка.

Фіксацію чи відміну транзакції виконують методи Commit() та Rollback() які описуються в п. 2.

З класу DbTransaction успадковані класи конкретних провайдерів:

  • SqlTransaction;
  • OleDbTransaction;
  • OdbcTransaction.

Ці класи безпосередньо використовуються при програмуванні задач, пов’язаних з обробкою транзакцій.

 

2. Методи класу DbTransaction. Огляд

У кожному класі провайдера, що відповідає транзакції, реалізовано три базові методи:

  • Rollback() – відкочує транзакцію з стану очікування;
  • Commit() – фіксує транзакцію в базі даних;
  • Save() – створює точку збереження в транзакції, яка може використовуватись для відкату частини транзакції і задає ім’я точки збереження.

Сигнатура цих методів у класах SqlTransaction, OleDbTransaction, OdbcTransaction наступна:

void Rollback();
void Rollback(string transactionName);
void Commit();
void Save(string savePointName);

тут

  • savePointName – ім’я точки збереження;
  • transactionName – ім’я точки збереження, до якої відкочується транзакція при виклику методу Rollback().

Як видно з реалізацій методів, засоби C# ADO .NET дозволяють запам’ятовувати точку збереження, до якої може бути виконано відкат транзакції.

 

3. Властивість Connection. З’єднання з базою даних

Також у класі DbTransaction реалізовано властивість Connection. Ця властивість повертає об’єкт з’єднання, що зв’язаний з транзакцією або null якщо транзакція більше не дійсна. Оголошення властивості для різних провайдерів наступне:

SqlConnection SqlTransaction.Connection { get; }
OleDbConnection OleDbTransaction.Connection { get; }
OdbcConnection OdbcTransaction.Connection { get; }

 

4. Приклад роботи з транзакціями (на прикладі SQL-серверу)

Для роботи з транзакціями серверу MS SQL Server використовується клас SqlTransaction. Щоб виконати команду в SqlTransaction потрібно задати властивість Transaction в об’єкті класу SqlCommand. Об’єкт SqlTransaction створюється з допомогою методу BeginTransaction() класу SqlConnection.

Після початку SqlTransaction для класу SqlConnection повинні бути виконані всі запити до транзакції. Інакше виникне виключна ситуація InvalidOperationException з відповідним повідомленням.

Для фіксації даних у базі даних виконується метод Commit() класу SqlTransaction. Для відкату транзакції потрібно викликати метод Rollback().

Демонструється метод, що виконує транзакцію INSERT для заданого з’єднання

// Метод, що виконує транзакцію INSERT
void ExecuteSqlTransaction2(SqlConnection connection)
{
  // Змінити ім'я групи
  // 1. Оголосити внутрішні змінні
  int rows; // к-сть змінених рядків

  // 2. Сформувати текст SQL-запиту зміни таблиці
  //    Старе ім'я групи: textBox1
  //    Нове ім'я групи: textBox2
  string sqlText = "INSERT INTO [Group] (NameGroup) VALUES (\'" +
    textBox1.Text + "\')";

  // 4. Змінити ім'я групи в базі даних
  try  
  {
    // 4.1. Відкрити з'єднання
    connection.Open();

    // 4.2. Створити транзакцію
    using (SqlTransaction transaction =
      connection.BeginTransaction()) // метод BeginTransaction()
    {
      // Створити об'єкт з SQL-командою
      SqlCommand command = new SqlCommand(sqlText, connection, transaction);

      // Заповнити rows
      rows = command.ExecuteNonQuery();

      // Зафіксувати зміни в базі даних
      transaction.Commit();

      // transaction.Rollback(); - виконати відкат транзакції
      label2.Text = rows.ToString();
    }
  }
  catch (SqlException ex)
  {
    MessageBox.Show(ex.Message);
  }
  finally
  {
    // 4.5. Закрити з'єднання
    connection.Close();

    // команда SELECT * FROM [Group]
    ExecuteSqlCommandSelectGroup(connection);
  }
}

 

5. Приклад створення та фіксування транзакції для таблиці товарів

Демонструється спрощений приклад виконання SQL-запиту з підтримкою транзакції, яка вносить додатковий рядок в таблицю Product бази даних з іменем MyDatabase.

Таблиця має наступні поля

ID_Product Name Price Count Date Note

Призначення полів таблиці наступне:

  • ID_Product – унікальний ідентифікатор, код товару.
  • Name – назва товару;
  • Price – вартість товару;
  • Count – кількість одиниць товару;
  • Date – дата отримання товару;
  • Note – додатковий опис (примітка) товару.

Нижченаведений фрагмент коду відображає створення та фіксування транзакції для додатку типу Windows Forms (обробник події кліку на кнопці).

private void button10_Click(object sender, EventArgs e)
{
  // 1. Створити рядок Connection String
  SqlConnectionStringBuilder sb = new SqlConnectionStringBuilder();
  sb.DataSource = "(localdb)\\ProjectModels";
  sb.InitialCatalog = "MyDatabase";
  sb.IntegratedSecurity = true;

  // 2. Створити з'єднання на основі Connection String
  SqlConnection connection = new SqlConnection(sb.ConnectionString);

  // 3. Відкрити з'єднання
  connection.Open();

  // 4. Створити транзакцію на основі з'єднання
  SqlTransaction transaction = connection.BeginTransaction();

  // 5. Створити команду на мові SQL з транзакцією
  string sqlCmd = "INSERT INTO Product (ID_Product, [Name], [Price], [Count], [Date], [Note]) " +
    "VALUES (16, 'Multicooker Bosh', 6500.00, 3, '2022-04-12', 'Bosh DT-280A')";
  SqlCommand command = new SqlCommand(sqlCmd, connection);

  // 6. Додати до команди sqlCmd транзакцію
  command.Transaction = transaction;

  // 7. Виконати інструкцію Transact-SQL для заданого підключення,
  //    повертається кількість рядків які змінені
  int rowsAffected = command.ExecuteNonQuery();

  // 8. Зафіксувати транзакцію
  command.Transaction.Commit();

  // 9. Вивести кількість змінених рядків
  label1.Text = "Rows affected = " + rowsAffected.ToString();

  // 10. Закрити з'єднання
  connection.Close();
}

Об’єкт, що реалізує транзакцію для з’єднання connection створюється викликом

SqlTransaction transaction = connection.BeginTransaction();

Після цього цей об’єкт додається до властивості Transaction об’єкту типу SqlCommand шляхом викликів

SqlCommand command = new SqlCommand(sqlCmd, connection);
command.Transaction = transaction;

Для виконання SQL-команди, що представлена об’єктом command, застосовується інструкція

command.ExecuteNonQuery();

Транзакція фіксується з допомогою виклику методу Commit() як показано нижче

command.Transaction.Commit();

Після такого виклику зміни фіксуються в базі даних.

Якщо після виконання SQL-запиту потрібно відмінити транзакцію, то викликається метод Rollback()

command.Transaction.Rollback();

 

6. Приклад створення точки збереження та відкату транзакції. Методи Save(), Rollback(string)

Точка збереження задається з допомогою методу

void Save(string savePointName);

тут savePointName – ім’я цієї точки збереження.

Метод

void Rollback(string transactionName);

відкочує транзакцію зі стану очікування і задає транзакцію або ім’я точки збереження. Попередньо точка збереження повинна бути запам’ятована в методі Save().

Приклад, що демонструє приблизну послідовність дій при взаємодії методів Save() та Rollback() наступна

// 1. Відкрити з'єднання
connection.Open();

// 2. Створити транзакцію на основі з'єднання
SqlTransaction transaction = connection.BeginTransaction();

// 3. Створити команду на мові SQL з транзакцією
string sqlCmd = "................................"; // тут задається текст команди

// 4. Створити об'єкт SqlCommand
SqlCommand command = new SqlCommand(sqlCmd, connection);

// 5. Додати до команди sqlCmd транзакцію
command.Transaction = transaction;

// 6. Сформувати точку збереження
string savePointName = "Save Point 1";
transaction.Save(savePointName);

// 7. Викликати запит, який змінює базу даних
int rowsAffected = command.ExecuteNonQuery();

// 8. Тут можуть бути деякі інші дії
// ...

// 9. Зробити відкат транзакції до точки збереження
transaction.Rollback(savePointName);