---
url: /docs/database/queries.md
---
# 查询写法

## 默认实时查询

业务接口使用 `ctx.db`。认证、组织权限、积分、订阅以及写入后的立即读取不能选 `dbCached`。缓存只在产品明确允许短期旧数据时使用。

## 按当前用户隔离

```ts
const runs = await ctx.db.query.toolRun.findMany({
  where: (run, { eq }) => eq(run.userId, ctx.user.id),
  orderBy: (run, { desc }) => [desc(run.createdAt)],
  limit: 20,
});
```

示例需要私有接口提供有效 `ctx.user`。读取和更新都带身份条件，不能先仅按记录 ID 查出敏感数据，再依靠前端隐藏。

## 组织权限

活动组织 ID 只代表当前范围。对组织资源查询成员表，同时匹配组织和当前用户；管理操作再检查 `owner` 或 `admin`。成员移除后旧会话不能继续拥有原权限。

## 列表与性能

明确排序和数量上限，返回所需列即可。大量数据使用稳定分页字段；避免循环逐条查询形成多次数据库往返。索引应与实际过滤和排序匹配，通过查询计划检查后再添加。

## 事务与唯一约束

积分余额更新、流水插入和保存结果需要按业务语义形成事务。唯一事件键防止并发或重试重复发放；非负余额约束防止越界扣款。网络响应丢失不代表服务端没执行，不能无条件重试非幂等操作。

## 测试

验证跨用户读取、跨组织写入、并发重复事件、余额不足和事务失败回滚。使用真实数据库约束测试这些边界，避免仅模拟查询函数返回值。
