Mysql Node.js中的多个SQL查询
我正在为Mysql Node.js中的多个SQL查询,mysql,node.js,express,Mysql,Node.js,Express,我正在为用户注册制定路线,我需要使用多个查询,以便确定数据库中是否存在用户名和电子邮件 我的第一个解决方案是创建一个连接。query内部连接。query但它不起作用 const { username, email, password, confirm } = req.body var error_mssg = [] connection.query( `SELECT COUNT(*) as usernameCount FROM adminuser WHERE username="$
用户注册制定路线
,我需要使用多个查询
,以便确定数据库中是否存在用户名
和电子邮件
我的第一个解决方案是创建一个连接。query
内部连接。query
但它不起作用
const { username, email, password, confirm } = req.body
var error_mssg = []
connection.query(
`SELECT COUNT(*) as usernameCount FROM adminuser WHERE username="${username}"`,
(err, data) => {
if (err) throw err;
if(data[0].usernameCount){
error_mssg.push("username already exist")
}
connection.query(
`SELECT COUNT(*) as emailCount FROM adminuser WHERE email="${email}"`,
(err, data) => {
if (err) throw err;
if (data[0].emailCount > 0){
error_mssg.push("email aready exist")
}
}
);
我还尝试在我的mysql.createConnection
中添加multiplestatems:true
,这很好,但我记得我仍然需要建立另一个连接。如果在数据库中找不到相同的username/email
,如果password==confirm
,则查询
connection.query(
`SELECT COUNT(*) as usernameCount FROM adminuser WHERE username="${username}";
SELECT COUNT(*) as emailCount FROM adminuser WHERE email="${email}"`,
(err, data) => {
if (err) throw err;
if(data[0][0].usernameCount){
error_mssg.push("username already exist")
}
if(data[1][0].emailCount){
error_mssg.push("email already exist")
}
if(password === confirm){
if(error_mssg.lenght > 0){
*******query to insert user information*******
}else{
res.send(error_mssg)
}
}else{
error_mssg.push("password does not match")
res.send(error_mssg)
}
}
);
如果error\u mssg
为空,如何使用多个查询
,然后插入数据。您可以尝试使用异步
查询。在同一个查询中尝试使用多个语句时,最好使用相同的方法
const usernameCount = await db.query( `SELECT COUNT(*) as usernameCount FROM adminuser WHERE username="${username}"` );
const emailCount = await db.query( `SELECT COUNT(*) as emailCount FROM adminuser WHERE email="${email}"` );
您可以尝试使用async
查询。在同一个查询中尝试使用多个语句时,最好使用相同的方法
const usernameCount = await db.query( `SELECT COUNT(*) as usernameCount FROM adminuser WHERE username="${username}"` );
const emailCount = await db.query( `SELECT COUNT(*) as emailCount FROM adminuser WHERE email="${email}"` );
注射
首先,关闭注入漏洞。用户输入不应被信任,也不应直接传递给另一个子系统。最好的方法是在侧通道中传递用户数据;在SQL中,这意味着使用准备好的查询。例如,您可以使用connection.execute
,而不是connection.query
:
connection.execute(
'SELECT Count(*) AS usernameCount FROM adminuser WHERE username=?',
[username],
(err, data) => {...}
)
可用的MySQL驱动程序可能只支持逃逸参数和模拟准备的语句,但这比没有什么好(尽管如果是这样的话,您应该认真考虑切换到支持准备语句的一个):
逻辑错误
仔细查看多语句示例中的块:
if(password === confirm){
if(error_mssg.lenght > 0){
*******query to insert user information*******
}else{
res.send(error_mssg)
}
...
请注意,如果有错误消息,则插入用户信息,如果没有,则返回(空)错误消息列表。这与你想要的正好相反。调试器可以帮助捕获这种逻辑错误
您可以发送所有错误消息,而不是仅在密码不匹配时发送存在错误消息。通过这种方式,用户可以一次更正所有错误,而不必仅提交以发现其他错误。这也将更好地将请求验证与请求处理分开
if (password !== confirm) {
error_msgs.push("passwords do not match");
}
if (error_msgs.length) {
res.send(error_msgs);
} else {
// create new user
...
}
存在性检验
查询现有记录的另一种方法是使用单个查询来检查adminuser
数据库中的现有用户名和电子邮件地址。与链式查询或wait
s相比,这具有效率优势,因为一个查询不需要等待另一个查询完成(尽管后两个查询的性能成本可能可以忽略不计)
由于这两个字段是同一数据库中的独立列,因此查询非常简单:
SELECT username, email FROM adminuser WHERE username=? OR email=?;
应通过使用unique
索引在模式中反映用户名和电子邮件应唯一的数据要求。这将限制结果行最多为2行(每个值的最大出现次数为1),然后可以检查是否存在唯一值
connection.execute(
'SELECT username, email FROM adminuser WHERE username=? OR email=?;',
[username, email],
(err, data) => {
if (err) throw err;
/*** Validate user creation request ***/
/* There should be at most 2 rows, with at most 1 occurrence each of `username` and `email`. */
for (var iRow=0; iRow < data.length; ++iRow) {
if (username == data[iRow].username) {
error_msgs.push("username already exists");
}
if (email == data[iRow].email) {
error_msgs.push("email already exists");
}
}
if (password !== confirm) {
error_msgs.push("passwords do not match");
}
/*** Handle user creation request ***/
if (error_msgs.length) {
res.send(error_msgs);
} else {
// create new user
...
}
}
);
其他设计注意事项
示例代码混合了两个不同的关注点:数据库访问和请求处理(validation&c.)。会减少。一个模块(数据访问层)应处理数据库中用户的管理(例如,检查现有记录中的用户名或电子邮件,添加新用户),另一个模块应通过向DAL发出适当的调用(可能是间接的)来处理用户创建请求(验证和用户创建)。特别是,SQL语句和数据库调用不应出现在请求处理程序中。请求处理程序可能类似于:
async function validateUserCreationRequest(req) {
const { username, email, password, confirm } = req.body;
var error_msgs = [],
userExists = await User.exists({ username, email }); // here, User is responsible for accessing the DAL
if (userExists) {
if (userExists.usernameCount) {
error_msgs.push("username already exists");
}
if (userExists.emailCount) {
error_msgs.push("email already exists");
}
}
if (password !== confirm) {
error_msgs.push("passwords do not match");
}
if (error_msgs.length) {
return error_msgs;
}
return null;
}
function createUser(req) {
return User.create(req); // again, User is responsible for accessing the DAL
}
function handleUserCreationRequest(req) {
var errors = validateUserCreationRequest(req);
if (errors) {
res.send(errors);
} else {
createUser(req);
}
}
注射
首先,关闭注入漏洞。用户输入不应被信任,也不应直接传递给另一个子系统。最好的方法是在侧通道中传递用户数据;在SQL中,这意味着使用准备好的查询。例如,您可以使用connection.execute
,而不是connection.query
:
connection.execute(
'SELECT Count(*) AS usernameCount FROM adminuser WHERE username=?',
[username],
(err, data) => {...}
)
可用的MySQL驱动程序可能只支持逃逸参数和模拟准备的语句,但这比没有什么好(尽管如果是这样的话,您应该认真考虑切换到支持准备语句的一个):
逻辑错误
仔细查看多语句示例中的块:
if(password === confirm){
if(error_mssg.lenght > 0){
*******query to insert user information*******
}else{
res.send(error_mssg)
}
...
请注意,如果有错误消息,则插入用户信息,如果没有,则返回(空)错误消息列表。这与你想要的正好相反。调试器可以帮助捕获这种逻辑错误
您可以发送所有错误消息,而不是仅在密码不匹配时发送存在错误消息。通过这种方式,用户可以一次更正所有错误,而不必仅提交以发现其他错误。这也将更好地将请求验证与请求处理分开
if (password !== confirm) {
error_msgs.push("passwords do not match");
}
if (error_msgs.length) {
res.send(error_msgs);
} else {
// create new user
...
}
存在性检验
查询现有记录的另一种方法是使用单个查询来检查adminuser
数据库中的现有用户名和电子邮件地址。与链式查询或wait
s相比,这具有效率优势,因为一个查询不需要等待另一个查询完成(尽管后两个查询的性能成本可能可以忽略不计)
由于这两个字段是同一数据库中的独立列,因此查询非常简单:
SELECT username, email FROM adminuser WHERE username=? OR email=?;
应通过使用unique
索引在模式中反映用户名和电子邮件应唯一的数据要求。这将限制结果行最多为2行(每个值的最大出现次数为1),然后可以检查是否存在唯一值
connection.execute(
'SELECT username, email FROM adminuser WHERE username=? OR email=?;',
[username, email],
(err, data) => {
if (err) throw err;
/*** Validate user creation request ***/
/* There should be at most 2 rows, with at most 1 occurrence each of `username` and `email`. */
for (var iRow=0; iRow < data.length; ++iRow) {
if (username == data[iRow].username) {
error_msgs.push("username already exists");
}
if (email == data[iRow].email) {
error_msgs.push("email already exists");
}
}
if (password !== confirm) {
error_msgs.push("passwords do not match");
}
/*** Handle user creation request ***/
if (error_msgs.length) {
res.send(error_msgs);
} else {
// create new user
...
}
}
);
其他设计注意事项
示例代码混合了两个不同的关注点:数据库访问和请求处理(validation&c.)。会减少。一个模块,数据访问层,应该处理管理databa中的用户