工作单元
工作单元(Unit of Work)是一种设计模式,用于跟踪业务事务期间对象的所有更改,并将多个数据库操作作为单个事务提交。在 MiCake 中,工作单元支持 Lazy 和 Immediate 两种初始化模式,以满足不同的性能和一致性需求。
什么是工作单元
Section titled “什么是工作单元”工作单元的核心职责:
- 跟踪变更:跟踪业务操作期间所有对象的变更
- 协调持久化:将所有变更作为一个事务提交
- 保证一致性:确保数据的完整性和一致性
- 管理事务:控制事务的开始、提交和回滚
ASP.NET Core 应用中的自动工作单元(推荐)
Section titled “ASP.NET Core 应用中的自动工作单元(推荐)”当你使用了MiCake.AspNetCore模块时,当MiCakeAspNetUowOption.IsAutoUowEnabled选项被启用时(默认为true),工作单元会在每次 HTTP 请求开始时自动创建,并在请求结束时自动提交或回滚,用户无须关心工作单元的生命周期管理。
// Startup.cs 或 Program.cs, 默认开启自动工作单元services.AddMiCakeWithDefault<MyModule, MyDbContext>();
// 可以手动设置,以禁用自动工作单元services.AddMiCakeWithDefault<MyModule, MyDbContext>(options =>{ options.AspNetConfig = asp => { asp.UnitOfWork.IsAutoUowEnabled = false; };});Controller 示例:
public class OrderController : ControllerBase{ private readonly IRepository<Order> _orderRepository;
public OrderController(IRepository<Order> orderRepository) { _orderRepository = orderRepository; }
// ✅ 工作单元自动创建、提交或回滚 [HttpPost] public async Task<IActionResult> CreateOrder(CreateOrderDto dto) { var order = new Order(dto.CustomerId, dto.Items); await _orderRepository.AddAsync(order);
// UoW 会在 action 执行成功后自动提交 return Ok(order.Id); }}手动工作单元
Section titled “手动工作单元”对于非 Web 场景或需要精确控制的情况:
public class OrderService{ private readonly IUnitOfWorkManager _uowManager; private readonly IRepository<Order> _orderRepository;
public OrderService( IUnitOfWorkManager uowManager, IRepository<Order> orderRepository) { _uowManager = uowManager; _orderRepository = orderRepository; }
public async Task ProcessOrderAsync(int orderId) { // ✅ 使用 BeginAsync 创建工作单元(推荐) using var uow = await _uowManager.BeginAsync();
var order = await _orderRepository.FindAsync(orderId); order.Process();
// 提交事务 await uow.CommitAsync(); }}事务初始化模式
Section titled “事务初始化模式”MiCake 提供了两种事务初始化模式:Lazy(延迟)和 Immediate(立即),以满足不同的性能和一致性需求。
Lazy 模式(默认)
Section titled “Lazy 模式(默认)”事务在第一次数据库操作时才真正开启:
using var uow = await _uowManager.BeginAsync();// 此时事务尚未开启
var order = await _orderRepository.FindAsync(1);// 此时事务才开始
await uow.CommitAsync();// 提交事务特点:
- 性能最优:只在需要时才开启事务
- 适合场景:读多写少的操作、可能不需要事务的场景
- 延迟初始化:事务在第一次数据库操作时才创建
Immediate 模式
Section titled “Immediate 模式”事务在创建工作单元时立即开启:
var options = new UnitOfWorkOptions{ InitializationMode = TransactionInitializationMode.Immediate};
using var uow = await _uowManager.BeginAsync(options);// 事务立即开启
var order = await _orderRepository.FindAsync(1);// 直接使用已开启的事务
await uow.CommitAsync();特点:
- 一致性保证:确保事务从开始就存在
- 适合场景:关键业务操作、需要明确事务边界的场景
- 立即初始化:事务在 Begin 时就创建
| 场景 | 推荐模式 | 原因 |
|---|---|---|
| 常规 CRUD 操作 | Lazy | 性能更好,大部分操作都需要事务 |
| 关键业务操作 | Immediate | 确保事务一致性 |
| 可能回滚的操作 | Immediate | 避免延迟初始化带来的不确定性 |
| 高并发读操作 | Lazy | 减少不必要的事务开销 |
| 分布式事务 | Immediate | 需要明确的边界控制 |
通过 Attribute 控制
Section titled “通过 Attribute 控制”// Controller 级别:所有 Action 使用立即初始化[UnitOfWork(InitializationMode = TransactionInitializationMode.Immediate)]public class CriticalOperationController : ControllerBase{ // ...}
// Action 级别:特定操作使用立即初始化public class OrderController : ControllerBase{ [UnitOfWork(InitializationMode = TransactionInitializationMode.Immediate)] public async Task<IActionResult> CriticalOperation() { // 事务在 action 开始前就已开启 }}MiCake 支持嵌套工作单元,内层工作单元会自动加入外层事务:
public async Task ComplexOperationAsync(){ // 外层工作单元 using var outerUow = await _uowManager.BeginAsync();
var order = await _orderRepository.FindAsync(1); order.Update();
// 内层工作单元(自动嵌套) using var innerUow = await _uowManager.BeginAsync();
var product = await _productRepository.FindAsync(1); product.DecreaseStock();
await innerUow.CommitAsync(); // 标记内层完成 await outerUow.CommitAsync(); // 统一提交}嵌套规则:
- 内层事务自动加入外层事务
- 只有最外层工作单元负责最终提交
- 如果任意层失败,整个事务回滚
- 支持多层嵌套(建议不超过 3 层)
Attribute 声明式控制
Section titled “Attribute 声明式控制”启用工作单元
Section titled “启用工作单元”[UnitOfWork]public class ProductController : ControllerBase{ // 所有 Action 都会自动创建 UoW}禁用工作单元
Section titled “禁用工作单元”[DisableUnitOfWork]public class ReportController : ControllerBase{ // 纯查询 Controller,不需要事务}或在 Action 级别覆盖:
public class MixedController : ControllerBase{ // 默认启用 UoW
[DisableUnitOfWork] public async Task<IActionResult> GetCachedData() { // 此 Action 不创建 UoW }}自定义隔离级别
Section titled “自定义隔离级别”[UnitOfWork(IsolationLevel = IsolationLevel.Serializable)]public async Task<IActionResult> HighConsistencyOperation(){ // 使用最高隔离级别}只读操作优化
Section titled “只读操作优化”MiCake 会自动识别只读操作(根据 Action 名称):
public class OrderController : ControllerBase{ // 自动识别为只读(跳过事务提交) public async Task<IActionResult> GetOrder(int id) { } public async Task<IActionResult> FindOrders() { } public async Task<IActionResult> QueryOrders() { } public async Task<IActionResult> SearchOrders() { }}可通过配置自定义只读关键字:
services.AddMiCakeWithDefault<MyModule, MyDbContext>( miCakeAspNetConfig: options => { options.UnitOfWork.ReadOnlyActionKeywords = ["Get", "Find", "Query", "Search", "List", "Fetch"]; });禁用自动工作单元
Section titled “禁用自动工作单元”services.AddMiCakeWithDefault<MyModule, MyDbContext>( miCakeAspNetConfig: options => { options.UnitOfWork.IsAutoTransactionEnabled = false; });此时需要手动管理所有工作单元。
Savepoint(保存点)
Section titled “Savepoint(保存点)”在长事务中创建保存点,支持部分回滚:
using var uow = await _uowManager.BeginAsync();
// 执行一些操作await ProcessStep1();
// 创建保存点var savepoint = await uow.CreateSavepointAsync("step1");
try{ // 执行可能失败的操作 await ProcessStep2();}catch{ // 回滚到保存点,保留 step1 的更改 await uow.RollbackToSavepointAsync("step1");}
await uow.CommitAsync();using var uow = await _uowManager.BeginAsync();
try{ await ProcessOrder();
if (someCondition) { // 手动回滚 await uow.RollbackAsync(); return; }
await uow.CommitAsync();}catch{ // 异常时自动回滚 throw;}监听工作单元事件
Section titled “监听工作单元事件”using var uow = await _uowManager.BeginAsync();
uow.OnCommitting += (sender, args) =>{ _logger.LogInformation("UoW {Id} is committing", args.UnitOfWorkId);};
uow.OnCommitted += (sender, args) =>{ _logger.LogInformation("UoW {Id} committed successfully", args.UnitOfWorkId);};
uow.OnRolledBack += (sender, args) =>{ _logger.LogWarning(args.Exception, "UoW {Id} rolled back", args.UnitOfWorkId);};
await ProcessOrder();await uow.CommitAsync();ASP.NET Core 配置
Section titled “ASP.NET Core 配置”services.AddMiCakeWithDefault<MyModule, MyDbContext>( miCakeAspNetConfig: options => { // 启用/禁用自动事务(默认:true) options.UnitOfWork.IsAutoTransactionEnabled = true;
// 只读 Action 关键字 options.UnitOfWork.ReadOnlyActionKeywords = ["Find", "Get", "Query", "Search"]; });UnitOfWork 选项
Section titled “UnitOfWork 选项”var options = new UnitOfWorkOptions{ // 隔离级别(默认:ReadCommitted) IsolationLevel = IsolationLevel.ReadCommitted,
// 初始化模式(默认:Lazy) InitializationMode = TransactionInitializationMode.Lazy,
// 是否只读(默认:false) IsReadOnly = false,
// 超时时间(秒) Timeout = 30};
using var uow = await _uowManager.BeginAsync(options);✅ 推荐做法
Section titled “✅ 推荐做法”- 优先使用 BeginAsync()
// ✅ 好using var uow = await _uowManager.BeginAsync();
// ❌ 避免(仅用于向后兼容)using var uow = _uowManager.Begin();- 使用 using 语句确保 Dispose
// ✅ 好using var uow = await _uowManager.BeginAsync();// ... 操作await uow.CommitAsync();
// ❌ 差var uow = await _uowManager.BeginAsync();// ... 操作await uow.CommitAsync();// 忘记 Dispose!- 明确提交或回滚
using var uow = await _uowManager.BeginAsync();
try{ // ... 操作 await uow.CommitAsync(); // ✅ 明确提交}catch{ // Dispose 时会记录警告 throw;}- 合理使用 Attribute
// ✅ 在 Controller 级别声明,减少重复[UnitOfWork]public class OrderController : ControllerBase { }
// ✅ Action 级别覆盖特殊情况[DisableUnitOfWork]public async Task<IActionResult> GetCachedData() { }- 不要在循环中创建多个 UoW
// ❌ 差foreach (var order in orders){ using var uow = await _uowManager.BeginAsync(); await ProcessOrder(order); await uow.CommitAsync();}
// ✅ 好using var uow = await _uowManager.BeginAsync();foreach (var order in orders){ await ProcessOrder(order);}await uow.CommitAsync();- 不要在 UoW 外部使用 Repository
// ❌ 差var order = await _orderRepository.FindAsync(1); // 没有 UoW 上下文
// ✅ 好using var uow = await _uowManager.BeginAsync();var order = await _orderRepository.FindAsync(1);// ... 操作await uow.CommitAsync();- 避免过长的事务
// ❌ 差using var uow = await _uowManager.BeginAsync();await DoLotsOfWork(); // 10 分钟的操作await DoMoreWork();await uow.CommitAsync();
// ✅ 好 - 将长操作拆分await DoLotsOfWork(); // 不在事务中
using var uow = await _uowManager.BeginAsync();await DoCriticalWork(); // 只有关键部分在事务中await uow.CommitAsync();❌ 工作单元未完成警告
Section titled “❌ 工作单元未完成警告”// 错误:未明确提交或回滚using var uow = await _uowManager.BeginAsync();await ProcessOrder();// 忘记调用 CommitAsync() 或 RollbackAsync()// Dispose 时会记录警告:"UnitOfWork disposed without being completed"✅ 正确的处理
Section titled “✅ 正确的处理”using var uow = await _uowManager.BeginAsync();
try{ await ProcessOrder(); await uow.CommitAsync(); // ✅ 明确提交}catch (Exception ex){ await uow.RollbackAsync(); // ✅ 明确回滚 throw;}❌ 嵌套事务误用
Section titled “❌ 嵌套事务误用”// 错误:使用 requiresNew 创建新事务using var outerUow = await _uowManager.BeginAsync();using var innerUow = await _uowManager.BeginAsync(requiresNew: true);// 这会创建两个独立的事务,而不是嵌套✅ 正确的嵌套
Section titled “✅ 正确的嵌套”// 正确:不使用 requiresNew 参数using var outerUow = await _uowManager.BeginAsync();using var innerUow = await _uowManager.BeginAsync();// 内层会自动嵌套在外层事务中await innerUow.CommitAsync();await outerUow.CommitAsync();工作单元是 MiCake 中事务管理的核心,在框架中:
- ✅ Lazy 和 Immediate 模式 - 满足不同性能和一致性需求
- ✅ 嵌套事务支持 - 灵活的事务组合
- ✅ 声明式控制 - Attribute 简化配置
- ✅ 自动管理 - ASP.NET Core 集成
通过合理使用工作单元,您可以:
- 确保数据一致性
- 简化事务管理
- 提高代码可维护性
- 优化应用性能
下一步: