在上一篇文章《Nodejs学习:连接MySQL数据库》中学习了Nodejs连接MySQL数据库的几种方法,数据库连接上了之后就需要对数据库进行查询。本篇文章介绍一下查询MySQL数据库的方法。

查询方式

  上一篇文章中,我们用到了一种查询数据库的最基本的方法:connection.query(sqlString, callback)
  第一个参数是一个SQL语句,可以是任意的数据库语句,而第二个参数是一个回调函数,查询结果通过回调参数的方式返回。

1
2
3
4
5
6
connection.query(
'select * from book where author = "xyf" and country = "china"',
function(err, result) {
console.log(result);
}
);

  这是最简单的查询方式,但是存在着两个问题,一个是需要拼接字符串,比较繁琐;另一个是容易被sql注入攻击,因此我们有了第二种查询方式。

占位符注入查询

  第二种查询方式是采用了占位符的形式connection.query(sqlString, values, callback),这样就不需要进行恶心的字符串的拼接了。

1
2
3
4
5
6
7
connection.query(
'select * from book where author = ? and country = ?',
['xyf', 'china'],
function(err, result) {
console.log(result);
}
);

使用对象查询方式

  第三种查询方式我们将查询语句和查询值组合成一个对象来进行查询。它的形式是这样的:connection.query(object, callback)

1
2
3
4
5
6
7
8
9
10
connection.query(
{
sql: 'select * from book where author = ? and country = ?',
values: ['xyf', 'china'], // 作为对象的属性
timeout: 40000,
},
function(err, result) {
console.log(result);
}
);

组合查询方式

  将第二种和第三种方式可以结合起来使用,查询值作为query方法的一个参数,而不是作为对象中的一个属性。

1
2
3
4
5
6
7
8
9
10
11
connection.query(
{
sql: 'select * from book where author = ? and country = ?',
timeout: 40000,
// ['corner', 'us'] // 如果同时设置,那么此时不会生效
},
['xyf', 'china'], // 作为query函数的一个参数
function(err, result) {
console.log(result);
}
);

  需要注意的是,如果我们既将查询值作为对象的属性,又将其作为query函数的参数,这个时候函数中的参数将会覆盖对象的属性,也就是说此时只有参数的值生效。

解析查询值

  在进行数据库查询时,有一个重要的原则就是永远不要相信用户的输入。为什么不能相信用户的输入呢,首先让我们来了解一下SQL注入攻击。

SQL注入攻击

  所谓的SQL注入攻击,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。由于笔者并不是从事数据库方面的工作,也不是数据库方面的砖家,所以只能通过一个简单的DEMO来演示一下SQL注入攻击。
  假如我们拼接的SQL语句是这样的

1
2
var username = 'xyf';
var sql = 'select * from book where author = "'+username+'"';

  这里我们期待用户输入的username是Jack或者LiLi之类的,但是用户说我偏不,我就输入一串恶意代码:

1
2
var username = '"1 or 1=1';
var sql = 'select * from book where author = "'+username+'"';

  最后我们拼接的查询语句就变成了下面这样的:

1
select * from book where author = "" or 1=1

  如果读者对SQL语句有一些基本了解,就会知道如果把这段查询语句放到数据库中进行查询,那么所有用户的信息都被查出来了,但是这并不是我们想要看到的结果。

避免SQL注入攻击

  那么怎么才能避免SQL注入攻击呢?mysql提供了两种方法给我们,第一种方法就是每次查询时都把用户输入的数据都用escape()函数解析一下,有点类似预处理语句。

1
2
3
4
5
6
7
8
9
var authorname = 'user input';
connection.escape(authorname);
// 或者使用mysql.escape(authorname);
connection.query(
'select * from book where author = "'+authorname+'"',
function(err, result) {
console.log(result);
}
);

  第二种方法就是在查询时通过上面说到的占位符注入查询的查询方式来进行查询。但它内部的实现也是通过上面所说的escape()方法将用户输入解析了一下。推荐使用第二种方法来得简单快捷。

多语句查询

  mysql还支持多语句查询,但是由于某些安全原因(官方解释是因为如果值没有正确解析会导致SQL注入攻击)默认是被禁止的。那么让我们来打开这个“潘多拉魔盒”把。
  在创建数据库连接时首先把这个功能开启。

1
2
3
4
let connection = mysql.createConnection({
// 其他配置
multipleStatements: true,
});

  然后我们就可以使用多语句查询了。

1
2
3
4
5
6
7
8
9
10
11
connection.query(
{
sql: `select * from book where username = ?;
select * from book where username = ?;`,
},
['ace','xyf'],
function(err, rows, fields) {
if (err) throw err;
console.log('The solution is: ', rows);
}
);

查询结果

  通过查询语句返回的结果以数组的形式返回,如果是单语句查询,数组就是一个纯对象数组[obj1,obj2,...],数组中的每一个对象都是数据库中每一行的数据,只是以对象的方式返回。如果没有查询到数据,那么数组的长度就为0。
  但是如果是多语句(m条语句)的方式查询,虽然返回也是一个数组,但是数组中嵌套有n个数组,n的取值取决于你查询语句的条数m(即n=m)。

总结

  由于官方文档比较零碎,因此整理得不是很到位,有问题的地方希望大家指正。

本文地址: http://xieyufei.com/2016/12/05/Nodejs-Query-Mysql.html