插件安装
如果你使用的是vscode的话,我们都知道,里面和idea不一样,并没有自带的数据库连接管理,所以我们需要一个类似于idea的数据库管理。 在vs里我个人用着感觉还不错的两个插件
大家可以自行了解一下这两款工具,目前database client是有收费和免费的,免费的最多建立三个连接,但是个人感觉,比shell做的要体贴一点,各取所需吧。当然桌面级应用也是可以的。
数据库连接
与java一样,node并不能直接连接数据库,也需要类似jdbc这样的中间层的存在,在node中,我们推荐使用mySql2这个第三方库来辅助我们。下面是具体地址 sidorares.github.io/node-mysql2…
npm install --save mysql2 进行安装
具体配置
mysql2使用起来也非常方便,具体配置如下
const mysql = require("mysql2"); const connection = mysql.createConnection({ host: "localhost", // 数据库地址 user: "root", // 数据库用户名 password: "password", // 数据库密码 database: "mydatabase", // 要连接的数据库名 charset: "UTF8_GENERAL_CI", // 连接字符集,默认为 UTF8_GENERAL_CI connectTimeout: 10000, // 连接超时时间,单位为毫秒 multipleStatements: false, // 是否允许一个 query 中有多个 MySQL 语句,默认为 false });
此时我们就创立好的连接,我们可以测试一下,一个简单的sql语句,query函数传入两个参数,第一个是sql语句,第二个是回调函数,当然还有第三个,感兴趣的可以自己去了解一下
connection.query("select * from employee;", function (err, result) { console.log(result); });
这是数据库中的数据,控制台是执行程序后输出的结果
但是但是,并不止如此,我们不妨看一下,result是什么
connection.query( "update employee SET name = '张云6' WHERE id = 1", function (err, result) { console.log(result); } ); connection.end();//关闭数据库连接
我们以此来看一下这是什么
在 Node.js 中使用
mysql2
或其他 MySQL 客户端库执行数据库操作时,ResultSetHeader
对象的输出。这个对象提供了关于执行 SQL 语句后数据库状态的一些详细信息。
fieldCount:表示返回的字段数量。在 INSERT、UPDATE 或 DELETE 操作中,这个值通常是 0,因为这些操作不返回数据行。
affectedRows:表示操作影响的行数。例如,在一个更新语句中,这可能是指被更新的行数。
insertId:对于 INSERT 操作,这个字段表示插入操作生成的 AUTO_INCREMENT 值。如果插入操作没有生成 AUTO_INCREMENT 值,则这个字段为 0。
info:一个字符串,提供了关于操作的其他信息。例如,它可能包含匹配的行数、改变的行数和警告的数量。
serverStatus:一个数值,表示服务器状态。这个值通常用于诊断或检查服务器状态。
warningStatus:表示操作产生的警告数量。警告通常不是错误,但它们可能指示一些需要注意的问题。
changedRows:对于 UPDATE 操作,这个字段表示实际改变的行数(即,至少有一个字段被修改的行数)。
至此,我们已经完成了一个简单的数据库操作了 下面是一些进阶一点的方法,除了使用const mysql = require("mysql2");引入之外,mysql2还提供了promise的方式,具体的看下面的配置
const mysql = require("mysql2/promise"); async function test2() { const connection = await mysql.createConnection({ host: "localhost", // 数据库地址 user: "root", // 数据库用户名 password: "password", // 数据库密码 database: "mydatabase", // 要连接的数据库名 charset: "UTF8_GENERAL_CI", // 连接字符集,默认为 UTF8_GENERAL_CI connectTimeout: 10000, // 连接超时时间,单位为毫秒 multipleStatements: false, // 是否允许一个 query 中有多个 MySQL 语句,默认为 false }); const [result] = await connection.query("select * from employee;"); console.log(result); connection.end(); } test2();
依旧可以成功,但是因为使用了promise 的方式,在某些层面上会降低我们开发的复杂度,但是,我们可以发现,创建数据库的连接在函数中,难免我们会遇到函数多次执行的问题,如果我们没有即使将数据库的连接关闭掉,可能会引发更严重的问题 所以,我们引入数据池的概念
使用数据池
使用数据池,我们需要使用的不再是createConnection,而是mysql.createPool 具体配置如下
const mysql = require("mysql2/promise"); //使用连接池 const pool = mysql.createPool({ //建立连接池 host: "localhost", user: "root", password: "dizao06", database: "test", waitForConnections: true, multipleStatements: true, //允许运行多条sql }); async function test() { const [result] = await pool.query("select * from employee;"); console.log(result); pool.end(); } test();
这样我们就无需每次运行函数都创建一个数据库连接了
sql注入
思考这样一个问题,我要查询指定id的信息
很容易我们就想到,select * from employee where id=? 这样的语句,事实也确实如此 我们来写一下
const mysql = require("mysql2/promise"); //使用连接池 const pool = mysql.createPool({ //建立连接池 host: "localhost", user: "root", password: "dizao06", database: "test", waitForConnections: true, multipleStatements: true, //允许运行多条sql }); async function test(id) { const sql = `select * from employee where id=${id}`; const [result] = await pool.query(sql); console.log(result); pool.end(); } test(1);
结果也如我们所料,确实可以查询出来结果
但是我们考虑一个问题,这玩意最后不都是要被写成接口的吗,如果说用户来执行这个操作呢?用户带来的消息可信吗?很显然不可信,比如说,用户在控制台不知道用什么方法执行了你这个函数,正常执行当然可以,可是假如他这样执行呢,以这个数据为例
async function test(id) { console.log(id); const sql = `select * from employee where id=${id}`; const [result] = await pool.query(sql); console.log(result); pool.end(); } test("'';DELETE FROM company WHERE id = '4';");
你猜会如何呢?我传入的id是'';DELETE FROM company WHERE id = '4';的字符串,又通过模板字符串拼接了上去
数据已经被删掉了,仔细一想这不是一件很可怕的事情吗,你要查询指定的人,却删掉了整个数据库的文件,这是一件很怕的事情
为了解决sql注入,我们可以采用这样的方式,我们不再使用query去执行sql,而转而使用execute,在这里使用execute,我们可以将sql写成如下的格式
const sql = "select * from employee where id=?",
将需要传递参数的地方用?来代替,接着在执行的时候pool.execute(sql, [id]),
传入的第二个参数是一个数组,他会按照顺序以此放入?的位置
async function test(id) { const sql = "select * from employee where id=?"; const [result] = await pool.execute(sql, [id]); //防止sql注入 console.log(result); pool.end(); } test("'';DELETE FROM company WHERE id = '3';"); 最后查询为[]
async function test(id, id2) { const sql = "select * from employee where id=? or id=?"; const [result1] = await pool.execute(sql, [id, id2]); //防止sql注入 console.log(result1); pool.end(); } test("'';DELETE FROM company WHERE id = '3';", "3");
当然,这么写还是很麻烦很麻烦,当然存在其他方法比如orm框架,就不再这里介绍了