事务处理 #

一、事务概述 #

1.1 ACID特性 #

text
FaunaDB事务特性:
├── 原子性(Atomicity)
│   └── 事务中的所有操作要么全部成功,要么全部失败
├── 一致性(Consistency)
│   └── 事务前后数据保持一致状态
├── 隔离性(Isolation)
│   └── 并发事务互不干扰
└── 持久性(Durability)
    └── 已提交的事务永久保存

1.2 事务特点 #

text
FaunaDB事务特点:
├── 每个查询都是一个事务
├── 自动提交
├── 串行化隔离级别
├── 无需显式开始/提交
└── 支持Abort回滚

二、基本事务 #

2.1 单语句事务 #

javascript
// 单语句自动是事务
Create(Collection("users"), {
  data: { name: "Tom", email: "tom@example.com" }
})

2.2 多语句事务 #

javascript
// Do组合多个操作
Do(
  Create(Collection("users"), {
    data: { name: "Tom" }
  }),
  Create(Collection("profiles"), {
    data: { userId: "tom" }
  }),
  Create(Collection("audit_logs"), {
    data: { action: "user_created", timestamp: Now() }
  })
)

2.3 事务返回值 #

javascript
// Do返回最后一个表达式的值
Let(
  {
    result: Do(
      Create(Collection("users"), { data: { name: "Tom" } }),
      Create(Collection("profiles"), { data: { userId: "tom" } }),
      { success: true, message: "User created" }
    )
  },
  Var("result")
)

三、Abort回滚 #

3.1 Abort语法 #

javascript
// Abort中止事务
If(
  condition,
  doSomething,
  Abort("Transaction failed: reason")
)

3.2 条件回滚 #

javascript
// 条件检查后回滚
Let(
  {
    userRef: Ref(Collection("users"), "user_001"),
    balance: Select(["data", "balance"], Get(Var("userRef"))),
    amount: 100
  },
  If(
    LT(Var("balance"), Var("amount")),
    Abort("Insufficient balance"),
    Update(Var("userRef"), {
      data: {
        balance: Subtract(Var("balance"), Var("amount"))
      }
    })
  )
)

3.3 多条件验证 #

javascript
// 多条件验证
Let(
  {
    orderRef: Ref(Collection("orders"), "order_001"),
    order: Get(Var("orderRef")),
    status: Select(["data", "status"], Var("order")),
    total: Select(["data", "total"], Var("order")),
    payment: Select(["data", "payment"], Var("order"))
  },
  If(
    Not(Equals(Var("status"), "pending")),
    Abort("Order is not in pending status"),
    If(
      LT(Var("payment"), Var("total")),
      Abort("Payment amount is insufficient"),
      If(
        Not(Exists(Select(["data", "user"], Var("order")))),
        Abort("User not found"),
        Update(Var("orderRef"), {
          data: {
            status: "paid",
            paidAt: Now()
          }
        })
      )
    )
  )
)

四、转账事务 #

4.1 简单转账 #

javascript
// 转账事务
Let(
  {
    fromRef: Ref(Collection("accounts"), "account_001"),
    toRef: Ref(Collection("accounts"), "account_002"),
    amount: 100,
    
    fromAccount: Get(Var("fromRef")),
    toAccount: Get(Var("toRef")),
    
    fromBalance: Select(["data", "balance"], Var("fromAccount")),
    toBalance: Select(["data", "balance"], Var("toAccount"))
  },
  If(
    LT(Var("fromBalance"), Var("amount")),
    Abort("Insufficient balance"),
    Do(
      Update(Var("fromRef"), {
        data: { balance: Subtract(Var("fromBalance"), Var("amount")) }
      }),
      Update(Var("toRef"), {
        data: { balance: Add(Var("toBalance"), Var("amount")) }
      }),
      Create(Collection("transactions"), {
        data: {
          from: Var("fromRef"),
          to: Var("toRef"),
          amount: Var("amount"),
          timestamp: Now()
        }
      })
    )
  )
)

4.2 带锁定的转账 #

javascript
// 使用时间戳乐观锁
Let(
  {
    fromRef: Ref(Collection("accounts"), "account_001"),
    toRef: Ref(Collection("accounts"), "account_002"),
    amount: 100,
    expectedFromTs: Var("clientFromTs"),
    expectedToTs: Var("clientToTs")
  },
  Let(
    {
      fromAccount: Get(Var("fromRef")),
      toAccount: Get(Var("toRef")),
      currentFromTs: Select(["ts"], Var("fromAccount")),
      currentToTs: Select(["ts"], Var("toAccount"))
    },
    If(
      And(
        Equals(Var("currentFromTs"), Var("expectedFromTs")),
        Equals(Var("currentToTs"), Var("expectedToTs"))
      ),
      If(
        LT(Select(["data", "balance"], Var("fromAccount")), Var("amount")),
        Abort("Insufficient balance"),
        Do(
          Update(Var("fromRef"), {
            data: {
              balance: Subtract(
                Select(["data", "balance"], Var("fromAccount")),
                Var("amount")
              )
            }
          }),
          Update(Var("toRef"), {
            data: {
              balance: Add(
                Select(["data", "balance"], Var("toAccount")),
                Var("amount")
              )
            }
          }),
          Create(Collection("transactions"), {
            data: {
              from: Var("fromRef"),
              to: Var("toRef"),
              amount: Var("amount"),
              timestamp: Now()
            }
          })
        )
      ),
      Abort("Account was modified by another transaction")
    )
  )
)

五、库存事务 #

5.1 库存扣减 #

javascript
// 库存扣减事务
Let(
  {
    productRef: Ref(Collection("products"), "prod_001"),
    quantity: 5,
    
    product: Get(Var("productRef")),
    currentStock: Select(["data", "stock"], Var("product"))
  },
  If(
    LT(Var("currentStock"), Var("quantity")),
    Abort("Insufficient stock"),
    Update(Var("productRef"), {
      data: {
        stock: Subtract(Var("currentStock"), Var("quantity")),
        updatedAt: Now()
      }
    })
  )
)

5.2 订单创建事务 #

javascript
// 创建订单并扣减库存
Let(
  {
    userId: "user_001",
    items: [
      { productId: "prod_001", quantity: 2 },
      { productId: "prod_002", quantity: 1 }
    ]
  },
  Do(
    // 验证并扣减库存
    Foreach(
      Var("items"),
      Lambda("item",
        Let(
          {
            productRef: Ref(Collection("products"), Select("productId", Var("item"))),
            quantity: Select("quantity", Var("item")),
            product: Get(Var("productRef")),
            stock: Select(["data", "stock"], Var("product"))
          },
          If(
            LT(Var("stock"), Var("quantity")),
            Abort(Concat([
              "Insufficient stock for product: ",
              Select("productId", Var("item"))
            ])),
            Update(Var("productRef"), {
              data: {
                stock: Subtract(Var("stock"), Var("quantity"))
              }
            })
          )
        )
      )
    ),
    // 创建订单
    Create(Collection("orders"), {
      data: {
        user: Ref(Collection("users"), Var("userId")),
        items: Var("items"),
        status: "pending",
        createdAt: Now()
      }
    })
  )
)

六、并发控制 #

6.1 乐观并发控制 #

javascript
// 使用时间戳的乐观锁
Let(
  {
    ref: Ref(Collection("documents"), "doc_001"),
    expectedTs: Var("clientTs"),
    
    doc: Get(Var("ref")),
    currentTs: Select(["ts"], Var("doc"))
  },
  If(
    Equals(Var("currentTs"), Var("expectedTs")),
    Update(Var("ref"), {
      data: { content: Var("newContent") }
    }),
    Abort("Document was modified by another transaction")
  )
)

6.2 版本号控制 #

javascript
// 使用版本号
Let(
  {
    ref: Ref(Collection("documents"), "doc_001"),
    expectedVersion: Var("clientVersion"),
    
    doc: Get(Var("ref")),
    currentVersion: Select(["data", "version"], Var("doc"), 0)
  },
  If(
    Equals(Var("currentVersion"), Var("expectedVersion")),
    Update(Var("ref"), {
      data: {
        content: Var("newContent"),
        version: Add(Var("currentVersion"), 1)
      }
    }),
    Abort("Document version mismatch")
  )
)

6.3 重试机制 #

javascript
// 重试函数
CreateFunction({
  name: "retry_update",
  body: Query(
    Lambda(["ref", "updateFn", "maxRetries"],
      Let(
        {
          attempt: Query(
            Lambda(["retries"],
              Let(
                {
                  doc: Get(Var("ref")),
                  result: Var("updateFn")(Var("doc"))
                },
                If(
                  Equals(Var("result"), "retry"),
                  If(
                    LT(Var("retries"), Var("maxRetries")),
                    Call(Function("retry_update"), [
                      Var("ref"),
                      Var("updateFn"),
                      Var("maxRetries")
                    ]),
                    Abort("Max retries exceeded")
                  ),
                  Var("result")
                )
              )
            )
          )
        },
        Call(Var("attempt"), [0])
      )
    )
  )
})

七、事务最佳实践 #

7.1 保持事务简短 #

javascript
// 好的做法:简洁的事务
Do(
  Update(userRef, { data: { balance: newBalance } }),
  Create(transactions, { data: transactionData })
)

// 避免:复杂的长事务
Do(
  // 大量操作...
  // 可能导致超时
)

7.2 提前验证 #

javascript
// 提前验证条件
Let(
  {
    user: Get(userRef),
    product: Get(productRef),
    
    userValid: Equals(Select(["data", "status"], Var("user")), "active"),
    productValid: GT(Select(["data", "stock"], Var("product")), 0)
  },
  If(
    Not(Var("userValid")),
    Abort("User is not active"),
    If(
      Not(Var("productValid")),
      Abort("Product out of stock"),
    // 执行事务
    Do(
      // ...
    )
    )
  )
)

7.3 记录审计日志 #

javascript
// 带审计日志的事务
Let(
  {
    operation: "transfer",
    userId: "user_001"
  },
  Do(
    // 业务操作
    Update(accountRef, { data: { balance: newBalance } }),
    // 审计日志
    Create(Collection("audit_logs"), {
      data: {
        operation: Var("operation"),
        userId: Var("userId"),
        timestamp: Now(),
        details: { amount: 100 }
      }
    })
  )
)

八、实际应用示例 #

8.1 银行转账 #

javascript
// 完整的银行转账事务
Let(
  {
    fromAccountId: "account_001",
    toAccountId: "account_002",
    amount: 100,
    description: "Transfer"
  },
  Let(
    {
      fromRef: Ref(Collection("accounts"), Var("fromAccountId")),
      toRef: Ref(Collection("accounts"), Var("toAccountId")),
      
      fromAccount: Get(Var("fromRef")),
      toAccount: Get(Var("toRef")),
      
      fromBalance: Select(["data", "balance"], Var("fromAccount")),
      toBalance: Select(["data", "balance"], Var("toAccount"))
    },
    If(
      LT(Var("fromBalance"), Var("amount")),
      Abort("Insufficient balance"),
      If(
        Equals(Var("fromRef"), Var("toRef")),
        Abort("Cannot transfer to same account"),
        Do(
          // 更新账户余额
          Update(Var("fromRef"), {
            data: {
              balance: Subtract(Var("fromBalance"), Var("amount")),
              updatedAt: Now()
            }
          }),
          Update(Var("toRef"), {
            data: {
              balance: Add(Var("toBalance"), Var("amount")),
              updatedAt: Now()
            }
          }),
          // 创建交易记录
          Create(Collection("transactions"), {
            data: {
              type: "transfer",
              from: Var("fromRef"),
              to: Var("toRef"),
              amount: Var("amount"),
              description: Var("description"),
              status: "completed",
              timestamp: Now()
            }
          })
        )
      )
    )
  )
)

8.2 订单支付 #

javascript
// 订单支付事务
Let(
  {
    orderId: "order_001",
    paymentMethod: "credit_card"
  },
  Let(
    {
      orderRef: Ref(Collection("orders"), Var("orderId")),
      order: Get(Var("orderRef")),
      
      status: Select(["data", "status"], Var("order")),
      total: Select(["data", "total"], Var("order")),
      userId: Select(["data", "userId"], Var("order"))
    },
    If(
      Not(Equals(Var("status"), "pending")),
      Abort("Order is not in pending status"),
      Let(
        {
          userRef: Ref(Collection("users"), Var("userId")),
          user: Get(Var("userRef")),
          balance: Select(["data", "balance"], Var("user"))
        },
        If(
          LT(Var("balance"), Var("total")),
          Abort("Insufficient user balance"),
          Do(
            // 扣除用户余额
            Update(Var("userRef"), {
              data: {
                balance: Subtract(Var("balance"), Var("total")),
                updatedAt: Now()
              }
            }),
            // 更新订单状态
            Update(Var("orderRef"), {
              data: {
                status: "paid",
                paymentMethod: Var("paymentMethod"),
                paidAt: Now(),
                updatedAt: Now()
              }
            }),
            // 创建支付记录
            Create(Collection("payments"), {
              data: {
                order: Var("orderRef"),
                user: Var("userRef"),
                amount: Var("total"),
                method: Var("paymentMethod"),
                status: "completed",
                timestamp: Now()
              }
            })
          )
        )
      )
    )
  )
)

九、总结 #

事务处理要点:

特性 说明
ACID 原子性、一致性、隔离性、持久性
Do 组合多个操作
Abort 中止事务
乐观锁 使用时间戳或版本号
串行化 最高隔离级别

下一步,让我们学习用户定义函数!

最后更新:2026-03-27