C#: tranzacții pentru operații care reușesc împreună
Folosește o tranzacție OleDb pentru două actualizări C# legate. Confirmă numai după succesul complet și verifică păstrarea datelor când al doilea pas eșuează.
În acest material
Unele operații sunt corecte numai dacă toate modificările lor reușesc. Într-un transfer de puncte, scăderea de la primul cont și adăugarea la al doilea formează o singură operație logică. Dacă al doilea pas eșuează, primul nu trebuie păstrat. O tranzacție grupează modificările până la Commit sau Rollback.
Cum lucrezi cu exemplul
Exemplul se compilează ca aplicație de consolă .NET Framework 4.8. Rulează pe Windows, cu provider ACE compatibil cu arhitectura procesului și o copie de test Data/catalog.accdb. Arhiva conține codul și pașii de pregătire, nu un fișier Access preconstruit.
Descarcă sursele și instrucțiunile.
Ideea și pașii de implementare
În copia Access de test creează Accounts cu AccountId Number/Long Integer cheie primară și Balance Number/Long Integer. Adaugă (1,100) și (2,40). Comanda de debitare verifică în WHERE și fondurile disponibile. Toate comenzile folosesc aceeași conexiune și aceeași tranzacție.
Fiecare ExecuteNonQuery trebuie să afecteze exact un rând. Confirmăm numai după ambele verificări. La eroare, încercăm rollback și propagăm eroarea originală. Valoarea transferată este un întreg pozitiv; pentru bani reali ar trebui proiectate explicit unitatea, precizia și toate regulile financiare.
Exemplu și rezultat așteptat
Transferul a 30 de puncte produce soldurile 70 și 70, păstrând totalul 140. Dacă ID-ul destinației devine 99, creditarea afectează zero rânduri și tranzacția este anulată. Soldurile trebuie să rămână 100 și 40, dacă pornești din setul inițial.
Solduri: 100 și 40 → Debit 30; credit 30 → Ambele afectează 1 rând → Commit → 70 și 70.Mărește schema ↗
Codul complet
using System;
using System.Data;
using System.Data.OleDb;
using System.IO;
class Program {
static string ConnectionString() {
string path=Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"Data","catalog.accdb");
if(!File.Exists(path))throw new FileNotFoundException("Pregateste baza de test Data/catalog.accdb.");
var builder=new OleDbConnectionStringBuilder();
builder.Provider="Microsoft.ACE.OLEDB.12.0";builder.DataSource=path;
return builder.ConnectionString;
}
static void Main() {
int amount=30,from=1,to=2;
if(amount<=0 || from==to)throw new ArgumentException("Transfer invalid");
using(var connection=new OleDbConnection(ConnectionString())) {
connection.Open();using(var tx=connection.BeginTransaction()) {
try {
using(var debit=new OleDbCommand("UPDATE Accounts SET Balance = Balance - ? WHERE AccountId = ? AND Balance >= ?",connection,tx)) {
debit.Parameters.Add("amount",OleDbType.Integer).Value=amount;
debit.Parameters.Add("from",OleDbType.Integer).Value=from;
debit.Parameters.Add("minimum",OleDbType.Integer).Value=amount;
if(debit.ExecuteNonQuery()!=1)throw new InvalidOperationException("Debit refuzat");
}
using(var credit=new OleDbCommand("UPDATE Accounts SET Balance = Balance + ? WHERE AccountId = ?",connection,tx)) {
credit.Parameters.Add("amount",OleDbType.Integer).Value=amount;
credit.Parameters.Add("to",OleDbType.Integer).Value=to;
if(credit.ExecuteNonQuery()!=1)throw new InvalidOperationException("Destinatie inexistenta");
}
tx.Commit();Console.WriteLine("Transfer confirmat");
} catch {
try {tx.Rollback();} catch(OleDbException) { } catch(InvalidOperationException) { }
throw;
}
}
}
}
}
Greșeli și limite
Nu crea a doua conexiune pentru al doilea pas și nu uita să asociezi comanda tranzacției. Nu afișa succes după debitare. Nu ignora zero rânduri afectate. Testul cel mai important provoacă intenționat eșecul după primul pas și verifică faptul că nu există modificare parțială.
Exersează
Rulează succesul pe o copie proaspătă, apoi scenariul cu destinație inexistentă pe altă copie proaspătă. Verifică prin SELECT ambele solduri, nu doar mesajul consolei. Încearcă transferul de 130 de puncte și confirmă refuzul fără sold negativ.
Continuă parcursul
Parcursul complet de 50 de lecții
Lecția precedentă: C#: BindingSource și filtrarea unui DataTable
Lecția următoare: C#: parole, salt și verificare într-un proiect didactic.
Referință: documentația Microsoft.
Întrebări frecvente
Când apelez Commit?
După ce toate comenzile și verificările operației au reușit.
Ce se întâmplă dacă al doilea pas eșuează?
Tranzacția trebuie anulată, astfel încât primul pas să nu rămână aplicat singur.
Este suficientă aceeași conexiune?
Nu. Comenzile trebuie asociate și aceleiași tranzacții active.
Un pas mai departe
Autentifică-te pentru a păstra progresul în cont.