From ceba1c68f2015c985247e87056829eb07cbd3c35 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Mon, 26 Oct 2026 18:36:54 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E5=92=8C=E4=B8=8A=E4=BC=A0=E7=B4=A0=E6=9D=90=E5=9C=A8=20await?= =?UTF-8?q?=20=E5=89=8D=E5=90=8E=E7=9A=84=E5=B9=B6=E5=8F=91=E7=AB=9E?= =?UTF-8?q?=E6=80=81=EF=BC=9B=E8=A1=A5=E5=85=85=20SQLite=20=E5=86=99?= =?UTF-8?q?=E6=B3=95=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 注册 / 新建用户 / 批量建用户:先算密码哈希,再同步地查重和插入, 同名并发请求返回 400 而不是撞唯一约束变成 500 - 上传任务素材改用 INSERT ... ON CONFLICT DO UPDATE - CLAUDE.md 补充同步阻塞、行内大文本列、索引、类型差异等注意事项 - 忽略根目录的 db.sqlite3(线上数据备份) Co-Authored-By: Claude Opus 5.5 --- .gitignore | 1 + CLAUDE.md | 4 ++++ server/src/routes/account.ts | 9 ++++++--- server/src/routes/files.ts | 15 ++++++--------- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 2a16763..efe24ad 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ /media/ /redis/ /sqlite/ +/db.sqlite3* # 本地工具目录 .agents/ diff --git a/CLAUDE.md b/CLAUDE.md index e5df0f0..20a3c1d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -67,6 +67,10 @@ docker compose run --rm webpreview-api bun scripts/create-superuser.ts { password: z.string().min(6).max(20), }), ) - if (userExists(payload.username)) throw new HttpError(400, "用户已存在") await insertUser(payload) return c.json({ message: "创建成功" }) }) @@ -148,6 +150,8 @@ router.post("/batch", async (c) => { ) const ts = now() tx(() => { + // 算哈希期间可能有人建了同名用户,插入前在同一个同步事务里再查一次 + if (usernames.some(userExists)) throw new HttpError(400, "有些用户已经存在,创建失败") for (const u of users) { run( `INSERT INTO account_user @@ -172,7 +176,6 @@ router.post("/create", async (c) => { classname: z.string().trim().max(50).default(""), }), ) - if (userExists(payload.username)) throw new HttpError(400, "用户已存在") const id = await insertUser(payload) return c.json({ id, message: "创建成功" }) }) diff --git a/server/src/routes/files.ts b/server/src/routes/files.ts index 206599d..4a1a08e 100644 --- a/server/src/routes/files.ts +++ b/server/src/routes/files.ts @@ -96,15 +96,12 @@ for (const kind of ["challenge", "tutorial"] as const) { `tasks/${task.task_type}/${task.display}/${validFilename(name)}`, file, ) - if (existing) { - run(`UPDATE task_taskasset SET file = $file WHERE id = $id`, { file: stored, id: existing.id }) - } else { - run(`INSERT INTO task_taskasset (name, file, task_id) VALUES ($name, $file, $task_id)`, { - name, - file: stored, - task_id: task.id, - }) - } + // 上面 await 期间可能有同名上传先写入了,用 upsert 而不是按 existing 选 INSERT / UPDATE + run( + `INSERT INTO task_taskasset (name, file, task_id) VALUES ($name, $file, $task_id) + ON CONFLICT (task_id, name) DO UPDATE SET file = excluded.file`, + { name, file: stored, task_id: task.id }, + ) return c.json(assetOut({ name, file: stored })) })