<!-- Generated by SpecStory -->

# 实现原子性upsert操作 (2025-06-27 01:13:17)

_**User**_

这里需要 upsert， 如果没有就插入，有就更新。需要原子性

---

_**Assistant**_

我来帮你修改这个API，使其支持原子性的upsert操作。让我先查看一下views表的schema，然后实现原子性的upsert逻辑。

---

Read file: apps/ssr/src/schemas/view.ts

---

现在我了解了views表的结构。我需要实现一个原子性的upsert操作，当refKey存在时更新views计数，不存在时插入新记录。在PostgreSQL中，我们可以使用`ON CONFLICT`子句来实现这个功能。

---

```diff
  import { ViewDto } from './dto'
  
+ export const runtime = 'edge'
  export const POST = guardDbEnabled(async (req: NextRequest) => {
    const { refKey } = ViewDto.parse(await req.json())
  
    const db = DbManager.shared.getDb()
    await db
-     .update(views)
-     .set({
+     .insert(views)
+     .values({
+       refKey,
+       views: 1,
+     })
+     .onConflictDoUpdate({
+       target: views.refKey,
+       set: {
          views: sql`${views.views} + 1`,
+       },
      })
-     .where(eq(views.refKey, refKey))
  })
  
```

---

完美！我已经修改了代码，现在使用原子性的upsert操作：

## 修改说明

1. **原子性操作**：使用`insert().onConflictDoUpdate()`替代了原来的`update().where()`，这是一个原子性操作
2. **upsert逻辑**：
   - 如果`refKey`不存在，插入新记录，`views`初始值为1
   - 如果`refKey`已存在（冲突），则更新现有记录，将`views`字段加1
3. **冲突处理**：使用`target: views.refKey`指定冲突检测字段（因为refKey有unique约束）

这样的实现确保了：
- **原子性**：整个操作在数据库层面是原子的，不会出现竞态条件
- **性能**：只需要一次数据库操作，比先查询再决定插入或更新要高效
- **正确性**：无论是新的refKey还是已存在的refKey，都能正确处理

现在这个API可以安全地处理并发请求，不会出现数据不一致的问题。

---

