fix: 盲盒抽取使用事务 + 乐观锁防止并发抽到同一想法
- 将 findMany + update 包裹在 prisma.$transaction 中
- 使用 updateMany({ where: { id, status: "in_pool" } }) 保证原子性
- count=0 时返回 409 提示用户重试
This commit is contained in:
@@ -11,25 +11,39 @@ export const POST = apiHandler(async (req) => {
|
||||
|
||||
await requireMembership(roomId, userId);
|
||||
|
||||
const pool = await prisma.blindBoxIdea.findMany({
|
||||
where: { roomId, status: "in_pool" },
|
||||
select: { id: true },
|
||||
const userSelect = { id: true, username: true, avatar: true } as const;
|
||||
|
||||
const idea = await prisma.$transaction(async (tx) => {
|
||||
const pool = await tx.blindBoxIdea.findMany({
|
||||
where: { roomId, status: "in_pool" },
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
if (pool.length === 0) {
|
||||
throw new ApiError("盒子是空的,先往里面塞点想法吧!", 404);
|
||||
}
|
||||
|
||||
const picked = pool[Math.floor(Math.random() * pool.length)];
|
||||
|
||||
const { count } = await tx.blindBoxIdea.updateMany({
|
||||
where: { id: picked.id, status: "in_pool" },
|
||||
data: { status: "drawn", drawnById: userId },
|
||||
});
|
||||
|
||||
if (count === 0) {
|
||||
throw new ApiError("手慢了,再试一次", 409);
|
||||
}
|
||||
|
||||
return tx.blindBoxIdea.findUnique({
|
||||
where: { id: picked.id },
|
||||
include: {
|
||||
user: { select: userSelect },
|
||||
drawnBy: { select: userSelect },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
if (pool.length === 0) {
|
||||
throw new ApiError("盒子是空的,先往里面塞点想法吧!", 404);
|
||||
}
|
||||
|
||||
const picked = pool[Math.floor(Math.random() * pool.length)];
|
||||
|
||||
const idea = await prisma.blindBoxIdea.update({
|
||||
where: { id: picked.id },
|
||||
data: { status: "drawn", drawnById: userId },
|
||||
include: {
|
||||
user: { select: { id: true, username: true, avatar: true } },
|
||||
drawnBy: { select: { id: true, username: true, avatar: true } },
|
||||
},
|
||||
});
|
||||
if (!idea) throw new ApiError("抽取失败", 500);
|
||||
|
||||
return NextResponse.json({
|
||||
id: idea.id,
|
||||
|
||||
Reference in New Issue
Block a user