Express JS项目双表插入及重复电影数据校验实现问题
解决方案:Express + PostgreSQL 影评博客双表入库实现
核心需求
- 在
POST /submit请求中完成movie和post表的联动插入 - 检查电影是否已存在,存在则终止提交流程
- 加入异常处理,保障数据一致性
完整代码实现
app.post("/submit", async (req, res) => { const postTitle = req.body.titlepost; const articles = req.body.articles; const rating = req.body.rating; // 取最近获取的有效电影数据(假设每次提交对应最后一条拉取结果) const movieData = fetchResult[fetchResult.length - 1]; if (!movieData || movieData.title === "Please fetch some data") { return res.status(400).send("请先获取有效的电影数据"); } let client; try { client = await pool.connect(); // 开启事务,确保双表操作原子性 await client.query("BEGIN"); // 1. 检查电影是否已存在(用title+year做唯一校验,可替换为IMDB ID提升精准度) const checkMovieSql = `SELECT id FROM movie WHERE title = $1 AND year = $2`; const checkResult = await client.query(checkMovieSql, [movieData.title, movieData.year]); if (checkResult.rows.length > 0) { await client.query("ROLLBACK"); return res.status(400).send("该电影数据已存在,无法重复提交影评"); } // 2. 插入movie表并返回自增主键 const insertMovieSql = ` INSERT INTO movie (title, year, genre, director, image) VALUES ($1, $2, $3, $4, $5) RETURNING id `; const movieResult = await client.query(insertMovieSql, [ movieData.title, movieData.year, movieData.genre, movieData.director, movieData.image ]); const movieId = movieResult.rows[0].id; // 3. 插入post表,关联movie_id外键 const insertPostSql = ` INSERT INTO post (title, content, rating, movie_id) VALUES ($1, $2, $3, $4) `; await client.query(insertPostSql, [postTitle, articles, rating, movieId]); // 提交事务 await client.query("COMMIT"); // 重置缓存数组,避免重复提交 fetchResult = [{ title: "Please fetch some data", image: "/images/nodata.png" }]; res.redirect("/"); // 提交成功后跳转至首页或影评列表页 } catch (error) { // 异常时回滚事务 if (client) await client.query("ROLLBACK"); console.error("影评提交失败:", error); res.status(500).send("提交失败,请稍后重试"); } finally { // 释放数据库连接 if (client) client.release(); } });
关键逻辑说明
- 事务原子性:通过
BEGIN/COMMIT/ROLLBACK保证两张表的操作要么同时成功,要么同时回滚,避免出现单表数据残留的情况 - 重复数据校验:通过电影标题+年份组合查询,判断数据是否已存在,可根据业务需求替换为IMDB ID等更唯一的标识
- 外键关联实现:插入
movie表时用RETURNING id获取生成的主键,以此作为post表movie_id的关联值 - 连接资源管理:在
finally块中释放数据库连接,防止连接池资源泄漏 - 缓存重置:提交成功后重置
fetchResult数组,避免用户重复提交同一电影的影评
内容的提问来源于stack exchange,提问作者Sandi Miftah
相关产品推荐
相关产品推荐

