当业务有“要么都成功,要么都失败”的要求(如余额转账、库存扣减+订单创建),就必须使用事务。


TinyDb 的事务入口在 TinyDbEngine.BeginTransaction()

1. 最小事务模板

using var db = new TinyDb.Core.TinyDbEngine("tx.db");
var users = db.GetCollection<User>();
var orders = db.GetCollection<Order>();

using var tx = db.BeginTransaction();
try
{
    users.Insert(new User { Name = "新用户", Email = "new@example.com", Age = 20 });
    orders.Insert(new Order { OrderNumber = "ORD-001", TotalAmount = 99.9m });

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

2. 转账场景(推荐写法)

[Entity("accounts")]
public partial class Account
{
    [Id]
    public ObjectId Id { get; set; } = ObjectId.NewObjectId();
    [Index(Unique = true)]
    public string AccountNo { get; set; } = string.Empty;
    public decimal Balance { get; set; }
}

public static bool Transfer(
    TinyDb.Core.TinyDbEngine db,
    ObjectId fromId,
    ObjectId toId,
    decimal amount)
{
    var accounts = db.GetCollection<Account>();

    using var tx = db.BeginTransaction();
    try
    {
        var from = accounts.FindById(fromId);
        var to = accounts.FindById(toId);

        if (from == null || to == null) return false;
        if (from.Balance < amount) return false;

        from.Balance -= amount;
        to.Balance += amount;

        accounts.Update(from);
        accounts.Update(to);

        tx.Commit();
        return true;
    }
    catch
    {
        tx.Rollback();
        throw;
    }
}

3. 保存点(Savepoint)

保存点适合“一个大事务里有可回滚子步骤”的场景。

using var tx = db.BeginTransaction();

// 步骤 1:写入基础数据
step1();
var sp1 = tx.CreateSavepoint("after-step1");

// 步骤 2:写入扩展数据
step2();

// 步骤 3:高风险步骤
try
{
    step3();
}
catch
{
    // 只回滚到步骤1后的状态,保留 step1
    tx.RollbackToSavepoint(sp1);
}

tx.Commit();

4. 常见误区

  1. 误区:忘记 Commit()

    说明:using 结束时,活动事务会走回滚路径。

  2. 误区:在事务中做大量慢 I/O(HTTP、文件、外部 RPC)。

    说明:会延长持锁时间,增加冲突与超时概率。应把外部 I/O 放到事务外。

  3. 误区:把“查询”与“写入”跨越很长时间。

    说明:业务判断可能过期。应尽量缩短“读-改-写”窗口。

5. 事务配置建议

TinyDbOptions 中与事务相关的关键项:

var options = new TinyDb.Core.TinyDbOptions
{
    MaxTransactions = 100,
    TransactionTimeout = TimeSpan.FromMinutes(5),
    WriteConcern = TinyDb.Core.WriteConcern.Synced
};
  • MaxTransactions:限制并发事务数量。

  • TransactionTimeout:限制事务生存时间。

  • WriteConcern:提交时的持久化强度(详见进阶性能篇)。

6. 失败补偿与幂等建议

对于支付、库存等高价值场景,建议同时做:

  • 业务幂等键(如 RequestId)。

  • 事务内唯一约束(防重复写)。

  • 失败日志记录(便于追偿/重试)。

7. 小结

  • 事务解决一致性,保存点解决“局部回滚”。

  • 尽量缩短事务窗口,避免在事务中做慢操作。

  • 高价值业务配合幂等设计,而不是只依赖事务。

下一篇进入并发常见需求:异步 API 与取消令牌。