LiteOrm在线文档

事务处理

LiteOrm 支持两种事务管理方式:声明式事务和手动事务。

场景选型

场景 推荐方式 原因
标准业务服务方法 声明式事务 代码简洁,边界清晰
需要显式控制提交/回滚时机 手动事务 控制粒度更高
组合多个 DAO / Service 写入 声明式事务优先 更贴近业务封装
基础设施层、批处理、特殊事务边界 手动事务 更适合细粒度控制

1. 声明式事务

使用 [Transaction] 特性标记方法,框架自动管理事务的开启、提交和回滚。

1.1 基本用法

public class UserService : EntityService<User>
{
    private readonly IOrderService _orderService;

    public UserService(IOrderService orderService)
    {
        _orderService = orderService;
    }

    [Transaction]
    public async Task CreateUserWithOrder(User user, Order order)
    {
        await InsertAsync(user);
        order.UserId = user.Id;
        await _orderService.InsertAsync(order);
    }
}

1.2 嵌套调用

声明式事务支持嵌套,嵌套方法使用同一事务:

[Transaction]
public async Task TransferMoney(long fromId, long toId, decimal amount)
{
    var fromAccount = await _accountService.GetObjectAsync(fromId);
    var toAccount = await _accountService.GetObjectAsync(toId);

    fromAccount.Balance -= amount;
    toAccount.Balance += amount;

    await _accountService.Update(fromAccount);
    await Update(fromAccount);  // 同一事务中

    await _accountService.Update(toAccount);
    await Update(toAccount);    // 同一事务中
}

1.3 注意事项

1.4 业务闭环示例

[Transaction]
public async Task SubmitOrderAsync(CreateOrderInput input)
{
    var order = new Order
    {
        UserId = input.UserId,
        Amount = input.Amount
    };

    await _orderService.InsertAsync(order);

    foreach (var item in input.Items)
    {
        await _orderItemService.InsertAsync(new OrderItem
        {
            OrderId = order.Id,
            ProductId = item.ProductId,
            Quantity = item.Quantity
        });
    }

    await _auditLogService.InsertAsync(new AuditLog
    {
        Action = "SubmitOrder",
        RefId = order.Id.ToString()
    });
}

这个模式适合“主表 + 明细 + 审计日志”一类的典型业务事务。

1.5 来自 Demo 的回滚示例

LiteOrm.Demo\Demos\TransactionDemo.cs 里演示了一个很实用的失败回滚场景:先创建用户,再插入一条故意不合法的销售记录,让事务自动回滚。

var newUser = new User { UserName = "ThreeTierUser", Age = 25 };
var initialSale = new SalesRecord
{
    ProductName = new string('A', 300), // 故意超过字段长度,触发异常
    Amount = 1
};

bool success = await factory.BusinessService
    .RegisterUserWithInitialSaleAsync(newUser, initialSale);

这个例子很适合验证“异常发生后,主流程已插入的数据是否也被撤回”。

2. 手动事务

通过 SessionManager 手动控制事务。

2.1 基本用法

var sessionManager = SessionManager.Current;
sessionManager.BeginTransaction();
try
{
    // 执行多个操作
    await userService.InsertAsync(user);
    await orderService.InsertAsync(order);

    sessionManager.Commit();
}
catch
{
    sessionManager.Rollback();
    throw;
}

2.2 事务隔离级别

var sessionManager = SessionManager.Current;
sessionManager.BeginTransaction(IsolationLevel.ReadCommitted);
try
{
    // 操作
    sessionManager.Commit();
}
catch
{
    sessionManager.Rollback();
    throw;
}

2.3 查询也可以纳入事务边界

var sessionManager = SessionManager.Current;
sessionManager.BeginTransaction(IsolationLevel.ReadCommitted);
try
{
    var users = await userService.SearchAsync(u => u.Age >= 18);
    sessionManager.Commit();
}
catch
{
    sessionManager.Rollback();
    throw;
}

2.4 与声明式事务的取舍

3. 事务传播行为

LiteOrm 的事务传播行为:

场景 行为
无现有事务 创建新事务
有现有事务 加入现有事务(嵌套)
事务失败 全部回滚

4. 事务与 SessionManager

LiteOrm 使用 SessionManager 管理数据库连接及事务:

5. timestamp 与事务的关系

timestamp 乐观并发控制和事务不是互斥关系,它们解决的是两个不同问题:

典型组合方式是:

  1. 用事务包裹一个完整业务流程。
  2. 对关键实体更新时,使用 ObjectDAO<T>.Update(entity, timestamp)UpdateAsync(entity, timestamp)
  3. 当返回 false 时,将其视为并发冲突并中止当前流程。
[Transaction]
public async Task<bool> RenameUserAsync(int id, string newName)
{
    var user = await _userViewDao.GetObject(id).FirstOrDefaultAsync();
    if (user == null)
        return false;

    int originalVersion = user.Version;
    user.UserName = newName;
    user.Version = originalVersion + 1;

    return await _userDao.UpdateAsync(user, originalVersion);
}

建议:

相关链接