1. 为什么需要数据库事务?
想象你在银行转账的场景:A账户转100元给B账户。如果扣款成功但存款失败,整个业务就会产生数据混乱。事务(Transaction)正是为了解决这类"要么全做,要么不做"的场景而生,它通过ACID特性(原子性、一致性、隔离性、持久性)确保数据操作的完整性。
2. 搭建开发环境
2.1 技术栈说明
本教程采用:
- .NET 6.0
- MySqlConnector 2.3.0
- MySQL 8.0
2.2 安装NuGet包
dotnet add package MySqlConnector
3. 基础事务处理示例
using MySqlConnector;
public class TransactionDemo
{
public static void BasicTransaction()
{
// 创建连接字符串(根据实际配置修改)
var connectionString = "Server=localhost;Database=testdb;Uid=root;Pwd=123456;";
using var connection = new MySqlConnection(connectionString);
connection.Open();
// 开启事务
using var transaction = connection.BeginTransaction();
try
{
// 第一条更新命令
var cmd1 = new MySqlCommand(
"UPDATE accounts SET balance = balance - 100 WHERE id = 1",
connection,
transaction);
cmd1.ExecuteNonQuery();
// 第二条更新命令
var cmd2 = new MySqlCommand(
"UPDATE accounts SET balance = balance + 100 WHERE id = 2",
connection,
transaction);
cmd2.ExecuteNonQuery();
// 提交事务
transaction.Commit();
Console.WriteLine("事务执行成功");
}
catch (Exception ex)
{
// 回滚事务
transaction.Rollback();
Console.WriteLine($"事务回滚,原因:{ex.Message}");
}
}
}
代码解析:
BeginTransaction()
显式开启事务- 所有数据库操作使用同一个事务对象
- 异常捕获时执行回滚
- 无异常时手动提交事务
4. 进阶事务处理:保存点
public static void SavepointTransaction()
{
using var connection = new MySqlConnection(connectionString);
connection.Open();
using var transaction = connection.BeginTransaction();
try
{
// 第一步操作:创建订单
var createOrder = new MySqlCommand(
"INSERT INTO orders (user_id, amount) VALUES (1, 100)",
connection,
transaction);
createOrder.ExecuteNonQuery();
// 设置保存点
transaction.Save("AfterCreateOrder");
// 第二步操作:扣减库存
var updateStock = new MySqlCommand(
"UPDATE products SET stock = stock - 1 WHERE id = 123",
connection,
transaction);
int affected = updateStock.ExecuteNonQuery();
if (affected == 0)
{
// 回滚到保存点
transaction.Rollback("AfterCreateOrder");
Console.WriteLine("库存扣减失败,回滚订单创建操作");
}
else
{
transaction.Commit();
Console.WriteLine("所有操作成功完成");
}
}
catch
{
transaction.Rollback();
Console.WriteLine("整体事务回滚");
}
}
5. 关联技术:ADO.NET核心对象
- MySqlConnection:数据库物理连接
- MySqlCommand:执行SQL命令
- MySqlTransaction:事务控制对象
- MySqlDataReader:顺序读取查询结果
6. 应用场景分析
6.1 典型使用场景
- 金融交易系统(转账、支付)
- 电商库存管理
- 票务系统的座位锁定
- 批量数据处理
- 分布式系统补偿机制
6.2 不适用场景
- 单条简单查询
- 日志记录等非关键数据
- 实时性要求极高的操作
- 超大事务(处理超过10万条记录)
7. 技术优缺点对比
7.1 优势特性
- 数据一致性保障
- 完善的错误恢复机制
- 支持保存点嵌套
- 与C#语言深度集成
- 良好的性能表现(相比ORM)
7.2 潜在缺陷
- 需要手动管理连接和事务
- 长期持有事务影响并发性能
- 分布式事务支持有限
- 代码复杂度相对较高
8. 开发注意事项
- 连接管理:确保及时关闭连接(推荐使用using语句)
- 超时设置:合理配置CommandTimeout(建议5-30秒)
- 隔离级别:根据业务需求选择合适的级别
- 异常处理:捕获特定异常类型(MySqlException)
- 性能优化:事务范围最小化原则
- 重试机制:对可重试异常实现自动重试
- 日志记录:详细记录事务开始/提交/回滚信息
9. 最佳实践总结
- 优先使用
using
语句管理资源 - 事务内避免长时间等待
- 重要操作添加保存点
- 使用异步方法提升吞吐量
- 定期检查未提交的事务
- 结合连接池优化性能
- 编写事务单元测试用例