Transactions are a fundamental concept in database management, ensuring data integrity by allowing a series of operations to be treated as a single, atomic unit. If any part of the transaction fails, the entire transaction is rolled back, leaving the database in its original state. ADO.NET provides robust support for managing database transactions through its transaction objects.
A database transaction adheres to the ACID properties:
In ADO.NET, transactions are managed using the DbTransaction
class and its provider-specific implementations (e.g., SqlTransaction
for SQL Server).
The process of managing a transaction typically involves the following steps:
BeginTransaction()
method on the connection object. This returns a transaction object.DbCommand
objects with the transaction. This ensures that commands are executed as part of the transaction.Commit()
method on the transaction object.Rollback()
method on the transaction object.Commit()
or Rollback()
within a finally
block or use a using
statement to guarantee transaction disposal and prevent resource leaks.
The following C# code demonstrates how to use a SqlTransaction
to perform a series of database operations:
using System;
using System.Data.SqlClient;
public class TransactionExample
{
public static void Main(string[] args)
{
string connectionString = "Server=myServerAddress;Database=myDataBase;User ID=myUsername;Password=myPassword;";
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlTransaction transaction = null;
try
{
// Begin the transaction
transaction = connection.BeginTransaction();
// Create commands and associate them with the transaction
SqlCommand command1 = new SqlCommand("UPDATE Accounts SET Balance = Balance - 100 WHERE AccountId = 1", connection, transaction);
command1.ExecuteNonQuery();
SqlCommand command2 = new SqlCommand("UPDATE Accounts SET Balance = Balance + 100 WHERE AccountId = 2", connection, transaction);
command2.ExecuteNonQuery();
// If both commands succeed, commit the transaction
transaction.Commit();
Console.WriteLine("Transaction committed successfully.");
}
catch (Exception ex)
{
// If an error occurs, roll back the transaction
if (transaction != null)
{
transaction.Rollback();
Console.WriteLine("Transaction rolled back. Error: " + ex.Message);
}
}
finally
{
// Ensure connection is closed
if (connection.State == System.Data.ConnectionState.Open)
{
connection.Close();
}
}
}
}
}
ADO.NET allows you to specify the isolation level for your transactions. The isolation level determines the degree to which one transaction must be isolated from the data modifications made by other concurrent transactions. Common isolation levels include:
ReadUncommitted
: Lowest isolation level. Reads may include uncommitted data.ReadCommitted
: Reads only include data that has been committed.RepeatableRead
: Guarantees that if a transaction reads a row multiple times, it will see the same row each time.Serializable
: Highest isolation level. Ensures that transactions are executed as if they were run one after another, preventing all concurrency conflicts.You can specify the isolation level when calling BeginTransaction()
:
SqlTransaction transaction = connection.BeginTransaction(System.Data.IsolationLevel.RepeatableRead);
DbConnection
(and provider-specific classes like SqlConnection
)
BeginTransaction()
: Starts a database transaction. Overloads allow specifying an isolation level.DbTransaction
(and provider-specific classes like SqlTransaction
)
Commit()
: Saves all changes made during the transaction.Rollback()
: Undoes all changes made during the transaction.Connection
: Gets the connection associated with the transaction.IsolationLevel
: Gets the isolation level of the transaction.DbCommand
(and provider-specific classes like SqlCommand
)
Transaction
: Sets or gets the transaction that the command should be executed within.Rollback()
is called if an error occurs.using
statements for connections, commands, and transactions for automatic resource management.