Express.js+MySQL+React CRUD新增FirstName重复校验实现
FirstName重复校验实现步骤
整个实现做三层覆盖,从数据兜底到前端交互全链路生效,不会出现漏校验问题。
1. 数据库层加唯一约束(必做,兜底防并发重复)
先在MySQL中执行以下SQL,给FirstName字段加唯一索引,从数据库层面禁止重复值插入:
ALTER TABLE emp_table ADD UNIQUE INDEX idx_firstname (FirstName);
2. 后端接口改造
原有后端接口存在两个问题:一是插入/更新前没有做重复校验,二是出错时仅打印控制台日志,没有给前端返回正确的错误状态码和提示,前端无法捕获错误。
改造新增接口(POST /api/post)
将原有/api/post路由替换为以下代码:
app.post("/api/post", (req, res) => { const { FirstName, LastName, FatherName, userCNIC, Contact, Gender } = req.body; // 先查询当前FirstName是否已存在 const checkDupSql = "SELECT id FROM emp_table WHERE FirstName = ? LIMIT 1"; db.query(checkDupSql, [FirstName], (checkErr, checkRes) => { if (checkErr) return res.status(500).send("服务器异常,请稍后重试"); if (checkRes.length > 0) return res.status(400).send("First Name已存在,请勿重复添加"); // 校验通过再执行插入 const insertSql = "INSERT INTO emp_table (FirstName, LastName, FatherName, userCNIC, Contact, Gender) VALUES (?, ?, ?, ?, ?, ?)"; db.query(insertSql, [FirstName, LastName, FatherName, userCNIC, Contact, Gender], (insertErr, insertRes) => { if (insertErr) { // 捕获唯一索引冲突错误,做兜底提示 if (insertErr.code === 'ER_DUP_ENTRY') return res.status(400).send("First Name已存在,请勿重复添加"); return res.status(500).send("数据添加失败,请重试"); } res.send("Values inserted!"); }); }); });
改造更新接口(PUT /api/update/:id)
编辑场景需要注意:如果用户没有修改FirstName,查询时要排除当前正在编辑的记录本身,否则会误判重复。将原有/api/update/:id路由替换为以下代码:
app.put("/api/update/:id", (req, res) => { const { id } = req.params; const { FirstName, LastName, FatherName, userCNIC, Contact, Gender } = req.body; // 查询重复时排除当前编辑的记录 const checkDupSql = "SELECT id FROM emp_table WHERE FirstName = ? AND id != ? LIMIT 1"; db.query(checkDupSql, [FirstName, id], (checkErr, checkRes) => { if (checkErr) return res.status(500).send("服务器异常,请稍后重试"); if (checkRes.length > 0) return res.status(400).send("First Name已存在,请更换后提交"); // 校验通过再执行更新 const updateSql = "UPDATE emp_table SET FirstName = ?, LastName = ?, FatherName = ?, userCNIC = ?, Contact = ?, Gender = ? WHERE id = ?"; db.query(updateSql, [FirstName, LastName, FatherName, userCNIC, Contact, Gender, id], (updateErr, updateRes) => { if (updateErr) { if (updateErr.code === 'ER_DUP_ENTRY') return res.status(400).send("First Name已存在,请更换后提交"); return res.status(500).send("数据更新失败,请重试"); } res.send(updateRes); }); }); });
3. 前端逻辑修复
原有前端代码存在两个逻辑bug,会导致错误提示无法正常展示:
- 没有统一阻止表单默认提交行为,会触发页面刷新
- 不管接口请求成功还是失败,都会直接弹出成功提示、500ms后跳转首页,用户看不到返回的错误信息
将AddEdit.js中的handleSubmit函数替换为以下代码即可:
const handleSubmit = (e) => { // 进入提交逻辑先阻止表单默认刷新行为 e.preventDefault(); const phoneno = /^\d{11,12}$/; const cnicno = /^\d{12,13}$/; // 基础字段校验 if (!FirstName || !LastName || !FatherName || !userCNIC || !Contact || !Gender) { toast.error("请填写所有必填字段"); return; } if (!Contact.match(phoneno)) { toast.error("请输入正确的手机号"); return; } if (!userCNIC.match(cnicno)) { toast.error("请输入正确的CNIC编号"); return; } if (!id) { // 新增场景 axios.post("http://localhost:5000/api/post", { FirstName, LastName, FatherName, userCNIC, Contact, Gender }).then(() => { // 只有请求成功才弹成功提示、清空表单、跳首页 toast.success("联系人添加成功"); setState(initialState); setTimeout(() => navigate("/"), 500); }).catch(err => { // 失败只弹错误,不跳页 toast.error(err.response.data); }) } else { // 编辑场景 axios.put(`http://localhost:5000/api/update/${id}`, { FirstName, LastName, FatherName, userCNIC, Contact, Gender }).then(() => { toast.success("联系人更新成功"); setState(initialState); setTimeout(() => navigate("/"), 500); }).catch(err => { toast.error(err.response.data); }) } };
两层校验的作用:应用层提前查询返回友好提示,交互体验更好;数据库唯一索引+错误捕获是兜底方案,防止高并发场景下出现重复数据。
内容的提问来源于stack exchange,提问作者SarfarazAhmed
相关产品推荐
相关产品推荐

