Node.js登录验证后更新MySQL登录计数报ER_PARSE_ERROR错误
问题原因
你遇到的报错和逻辑问题来自3个核心错误:
- SQL语法错误:
UPDATE语句不需要搭配INTO关键字,INTO是INSERT写入语句的专属语法,这就是抛出ER_PARSE_ERROR的直接原因 - 缺失WHERE限定条件:你写的更新语句没有指定要更新哪个用户,执行后会把
users表所有用户的登录次数字段都改掉,属于严重逻辑漏洞 - 执行时序问题:更新操作是异步回调,你没等更新执行完成就直接返回登录成功响应,极端场景下会出现页面跳转到首页时登录次数还没更新的情况;另外并发场景下先查值再加1的写法会出现计数不准的问题。
推荐实现方案(原子自增,无并发问题)
不需要提前查询用户历史登录次数,直接通过SQL内置的自增逻辑完成计数更新,性能更好,也不会出现并发计数错误,核心更新语句如下:
UPDATE users SET userLoginCount = userLoginCount + 1 WHERE id = ?
这个语句会自动找到对应用户,把登录次数在原有值基础上加1,不需要在Node.js层做数值计算。
修正后的完整代码
const login = async(req, res) => { const { username, password } = req.body; if (!username || !password) { return res.json({ status: 'error', error: 'Please enter your username and password' }) } db.query('SELECT * FROM users WHERE username = ?', [username], async(Err, result) => { if (Err) throw Err; if (!result.length || !await bcrypt.compare(password, result[0].password)) { return res.json({ status: 'error', error: 'Incorrect Username or password' }) } const token = jwt.sign( { id: result[0].id }, process.env.JWT_SECRET, { expiresIn: process.env.JWT_EXPIRES } ) // 注意:express的cookie配置过期字段是expires,不是expiresIn,原代码这里配置不生效 const cookieOption = { expires: new Date(Date.now() + process.env.COOKIE_EXPIRES * 24 * 60 * 60 * 1000), httpOnly: true } res.cookie('userRegistered', token, cookieOption) // 执行登录次数更新,加WHERE条件限定当前登录用户 db.query( 'UPDATE users SET userLoginCount = userLoginCount + 1 WHERE id = ?', [result[0].id], (error, results) => { if (error) throw error; console.log(results) console.log('user ' + username + ' logged in') // 等更新完成后再返回成功响应,避免时序问题 return res.json({ status: 'success', success: 'User has been logged In' }) } ) }) }
补充说明
如果你坚持要沿用「先查历史值→Node.js层加1→更新回表」的思路,也要注意必须加WHERE条件,对应更新语句写法如下,但非常不推荐高并发场景用这种写法:
// 不推荐,并发下会出现计数不准 db.query( 'UPDATE users SET userLoginCount = ? WHERE id = ?', [result[0].userLoginCount + 1, result[0].id], (error, results) => { // 回调逻辑 } )
内容的提问来源于stack exchange,提问作者seriously
相关产品推荐
相关产品推荐

