1. 事务的基本概念
事务(Transaction)是数据库操作中的一个重要概念,它代表一组必须全部成功或全部失败的操作单元。事务具有ACID四大特性:
- 原子性(Atomicity):事务中的所有操作要么全部完成,要么全部不完成
- 一致性(Consistency):事务执行前后,数据库从一个一致状态变到另一个一致状态
- 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务
- 持久性(Durability):一旦事务提交,其结果就是永久性的
在C#中,我们可以通过多种方式实现事务处理,包括ADO.NET事务、Entity Framework事务以及System.Transactions命名空间提供的分布式事务支持。
2. ADO.NET事务处理
2.1 基本事务处理
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlTransaction transaction = connection.BeginTransaction();
try
{
using (SqlCommand command = new SqlCommand("INSERT INTO Table1...", connection, transaction))
{
command.ExecuteNonQuery();
}
using (SqlCommand command = new SqlCommand("UPDATE Table2...", connection, transaction))
{
command.ExecuteNonQuery();
}
transaction.Commit();
Console.WriteLine("事务提交成功");
}
catch (Exception ex)
{
transaction.Rollback();
Console.WriteLine($"事务回滚,原因: {ex.Message}");
}
}
2.2 保存点(SavePoint)
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlTransaction transaction = connection.BeginTransaction();
try
{
// 第一个操作
using (SqlCommand command = new SqlCommand("INSERT INTO Table1...", connection, transaction))
{
command.ExecuteNonQuery();
}
// 创建保存点
transaction.Save("SavePoint1");
try
{
// 第二个操作
using (SqlCommand command = new SqlCommand("UPDATE Table2...", connection, transaction))
{
command.ExecuteNonQuery();
}
}
catch
{
// 回滚到保存点,而不是整个事务
transaction.Rollback("SavePoint1");
throw;
}
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
Console.WriteLine($"事务回滚,原因: {ex.Message}");
}
}
3. Entity Framework事务处理
3.1 DbContext自带事务
using (var context = new MyDbContext())
{
try
{
context.Products.Add(new Product { Name = "Product1" });
context.Customers.Add(new Customer { Name = "Customer1" });
// SaveChanges会自动开启并提交事务
context.SaveChanges();
Console.WriteLine("事务提交成功");
}
catch (Exception ex)
{
Console.WriteLine($"操作失败: {ex.Message}");
}
}
3.2 显式事务控制
using (var context = new MyDbContext())
{
using (var transaction = context.Database.BeginTransaction())
{
try
{
context.Products.Add(new Product { Name = "Product1" });
context.SaveChanges();
context.Customers.Add(new Customer { Name = "Customer1" });
context.SaveChanges();
transaction.Commit();
Console.WriteLine("事务提交成功");
}
catch (Exception ex)
{
transaction.Rollback();
Console.WriteLine($"事务回滚,原因: {ex.Message}");
}
}
}
4. System.Transactions分布式事务
当需要跨多个数据库或资源管理器进行事务操作时,可以使用System.Transactions。
using (TransactionScope scope = new TransactionScope())
{
try
{
// 第一个数据库操作
using (SqlConnection connection1 = new SqlConnection(connectionString1))
{
connection1.Open();
SqlCommand command1 = new SqlCommand("INSERT INTO Table1...", connection1);
command1.ExecuteNonQuery();
}
// 第二个数据库操作
using (SqlConnection connection2 = new SqlConnection(connectionString2))
{
connection2.Open();
SqlCommand command2 = new SqlCommand("UPDATE Table2...", connection2);
command2.ExecuteNonQuery();
}
scope.Complete();
Console.WriteLine("分布式事务提交成功");
}
catch (Exception ex)
{
Console.WriteLine($"分布式事务失败: {ex.Message}");
}
}
5. 事务隔离级别
C#支持不同的事务隔离级别,可以在创建事务时指定:
// ADO.NET中设置隔离级别
SqlTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted);
// Entity Framework中设置隔离级别
using (var transaction = context.Database.BeginTransaction(IsolationLevel.Serializable))
{
// ...
}
// System.Transactions中设置隔离级别
var options = new TransactionOptions
{
IsolationLevel = IsolationLevel.RepeatableRead,
Timeout = TimeSpan.FromSeconds(30)
};
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, options))
{
// ...
}
常用隔离级别:
- ReadUncommitted:最低隔离级别,允许读取未提交的数据
- ReadCommitted:只能读取已提交的数据(默认级别)
- RepeatableRead:确保在同一事务中多次读取相同数据结果一致
- Serializable:最高隔离级别,完全隔离事务
- Snapshot:使用行版本控制避免读取阻塞
6. 事务最佳实践
- 保持事务简短:长时间运行的事务会锁定资源,影响系统性能
- 合理设置隔离级别:根据业务需求选择最低合适的隔离级别
- 正确处理异常:确保在异常情况下事务能够正确回滚
- 避免分布式事务:分布式事务性能开销大,应尽可能避免
- 使用using语句:确保连接和事务对象能够正确释放
- 考虑重试机制:对于可能因并发冲突失败的操作,实现重试逻辑
7. 总结
C#提供了丰富的事务处理机制,从简单的ADO.NET事务到复杂的分布式事务支持。开发者应根据具体应用场景选择合适的事务处理方式,并遵循事务处理的最佳实践,以确保数据的一致性和系统的可靠性。