LiteOrm 支持两种事务管理方式:声明式事务和手动事务。
| 场景 | 推荐方式 | 原因 |
|---|---|---|
| 标准业务服务方法 | 声明式事务 | 代码简洁,边界清晰 |
| 需要显式控制提交/回滚时机 | 手动事务 | 控制粒度更高 |
| 组合多个 DAO / Service 写入 | 声明式事务优先 | 更贴近业务封装 |
| 基础设施层、批处理、特殊事务边界 | 手动事务 | 更适合细粒度控制 |
使用 [Transaction] 特性标记方法,框架自动管理事务的开启、提交和回滚。
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);
}
}
声明式事务支持嵌套,嵌套方法使用同一事务:
[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); // 同一事务中
}
[Transaction] 特性需要 Castle.Core 动态代理支持public 且通过接口调用才能生效[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()
});
}
这个模式适合“主表 + 明细 + 审计日志”一类的典型业务事务。
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);
这个例子很适合验证“异常发生后,主流程已插入的数据是否也被撤回”。
通过 SessionManager 手动控制事务。
var sessionManager = SessionManager.Current;
sessionManager.BeginTransaction();
try
{
// 执行多个操作
await userService.InsertAsync(user);
await orderService.InsertAsync(order);
sessionManager.Commit();
}
catch
{
sessionManager.Rollback();
throw;
}
var sessionManager = SessionManager.Current;
sessionManager.BeginTransaction(IsolationLevel.ReadCommitted);
try
{
// 操作
sessionManager.Commit();
}
catch
{
sessionManager.Rollback();
throw;
}
var sessionManager = SessionManager.Current;
sessionManager.BeginTransaction(IsolationLevel.ReadCommitted);
try
{
var users = await userService.SearchAsync(u => u.Age >= 18);
sessionManager.Commit();
}
catch
{
sessionManager.Rollback();
throw;
}
LiteOrm 的事务传播行为:
| 场景 | 行为 |
|---|---|
| 无现有事务 | 创建新事务 |
| 有现有事务 | 加入现有事务(嵌套) |
| 事务失败 | 全部回滚 |
LiteOrm 使用 SessionManager 管理数据库连接及事务:
timestamp 与事务的关系timestamp 乐观并发控制和事务不是互斥关系,它们解决的是两个不同问题:
timestamp:防止“后提交覆盖先提交”的丢失更新。典型组合方式是:
ObjectDAO<T>.Update(entity, timestamp) 或 UpdateAsync(entity, timestamp)。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);
}
建议:
timestamp 校验。