使用 NodeJS 开发,必不可少的肯定会涉及到数据存储,此篇就以 MySQL 为例来看数据库存取业务的开发。在使用 MySQL 之前,需要先安装 MySQL 驱动。

npm install mysql --save

1.1. 连接数据库

var mysql = require('mysql');

var conn = mysql.createConnection({
    host: '127.0.0.1',
    user: 'root',
    password: '111111',
    database: 'mydb',
    port: 3306
});

conn.connect();
// 查询
conn.query('select * from User', function(err, result) {
    console.log(result);
});
// 关闭数据库连接 -> 不是直接关闭,而是在所有query完成之后再关闭
conn.end();
// 关闭数据库连接 -> 直接关闭连接
// conn.destory();

使用 conn.query 方法查询数据,query 方法同样也可以进行 新增删除更新 操作,从回调函数的第二个参数中可以获取到对应的执行结果。

1.2. 增删改查

//新增
conn.query('insert into user (username,password) ...', function(err, result) {
    if (err) throw err;
    console.log(result); // result.insertId -> 获取新插入的数据的自增id
})

//删除
conn.query('delete from user where username="wupeigui"', function(err, result) {
    if (err) throw err;
    console.log(result);
})

// 更新 
conn.query('update user set id="1" where username="huxiaona"',function(err,result){
    if (err) {throw err};
    console.log("修改数据成功");
})

删除和更新,可以通过 result.affectedRows 来获取受影响的行数;

1.3. 数据库连接池

var connParams = {
    host: '127.0.0.1',
    user: 'root',
    password: '111111',
    database: 'mydb',
    port: 3306
};

var pool = mysql.createPool(connParams);
// 直接使用pool进行查询
pool.query('select * from User',function(err, rs, fields){
    console.log(rs);
});
// 共享一个连接
pool.getConnection(function(err, conn){
    conn.query('select * from User', function(err, rs) {
        console.log(rs);
        conn.release();
    });
});

1.4. 连接池配置选项

createConnection 方法还可以传入一些其它选项参数。

  • waitForConnections: 当连接池没有连接或超出最大限制时,设置为true且会把连接放入队列,设置为false会返回error
  • connectionLimit: 连接数限制,默认:10
  • queueLimit: 最大连接请求队列限制,设置为0表示不限制,默认:0

1.4.1. 连接释放

调用connection.release()方法,会把连接放回连接池,等待其它使用者使用!

1.4.2. 连接错误处理

var conn = 0;

function handleError() {
    var connParams = {
        host: '127.0.0.1',
        user: 'root',
        password: '1111110',
        database: 'mydb',
        port: 3306
    };
    conn = mysql.createConnection(connParams);
    conn.connect(function(err) {
        // 1
        if(err){ 
            // err.code === 'ER_ACCESS_DENIED_ERROR' -> 密码错误
            console.log(err);
        }
    });

    conn.on('error', function(err) {
        console.log('db error');
        // 如果是连接断开,自动重新连接
        if (err.code === 'PROTOCOL_CONNECTION_LOST') {
            handleError();
        } else {
            // err.code === 'ECONNRESET' -> mysql 进程死掉
            throw err;
        }
    });
}

handleError();

上面的代码可以处理 登录密码错误数据库宕机连接超时

  • 登录密码错误
ER_ACCESS_DENIED_ERROR
  • 数据库宕机
ECONNRESET
  • 连接超时/断开
PROTOCOL_CONNECTION_LOST

使用 root 账户修改 MySQLwait_timeout 参数,设为10秒;

~ mysql -u root -p
mysql> show variables like 'wait_timeout';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout  | 28800 |
+---------------+-------+
1 row in set (0.00 sec)

mysql> set global wait_timeout=10;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like 'wait_timeout';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout  | 10    |
+---------------+-------+
1 row in set (0.00 sec)

添加测试代码

function query(){
    console.log(new Date());
    var sql = "show variables like 'wait_timeout'";
    conn.query(sql, function (err, res) {
        console.log(res);
    });
}

setInterval(query, 15*1000);

1.4.3. 连接池超时

var selectSQL ="show variables like 'wait_timeout'";

pool.getConnection(function (err, conn) {
    if (err) console.log("POOL ==> " + err);
    function query(){
        conn.query(selectSQL, function (err, res) {
            console.log(new Date());
            console.log(res);
            conn.release();
        });
    }
    setInterval(query, 12 * 1000);
});

1.5. 事务

connection.beginTransaction(function(err) {
    if (err) { throw err; } 

    connection.query('INSERT INTO posts SET title=?', title, function(err, result) { 
        if (err) {  
             connection.rollback(function() { 
                 throw err; 
            }); 
        }

        var log = 'Post ' + result.insertId + ' added'; 

        connection.query('INSERT INTO log SET data=?', log, function(err, result) { 
            if (err) {  
                connection.rollback(function() { 
                    throw err; 
                }); 
            }
            connection.commit(function(err) { 
            if (err) {  
                connection.rollback(function() { 
                    throw err; 
                }); 
            } 
            console.log('success!'); 
            }); 
        }); 
    }); 
});

1.6. 转义

字符串转义

在使用客户端输入的值来组装查询语句时,需要对这些值进行正确的转义,以避免遭受 SQL注入 攻击。可以使用 escape() 方法来对这些值进行转义:

var sql = 'select * from User where id = ' + conn.escape("27 or id = 28");
console.log(sql);
conn.query(sql, function(err, resulst){
   console.log(resulst);
});

还可以在SQL语句中将要转义的值用问号 ? 来代替,再在调用 query() 方法时传入这些待转义的值:

conn.query('select * from User where id=? or id=?', [27, 28], function(err, rs){
    console.log(rs);
});

标识符转义

与字符串值的转义类似,标识符的转义可以使用 escapeId() 方法来实现:

var sorter = 'date';
var query = 'SELECT * FROM posts ORDER BY ' + mysql.escapeId(sorter);
console.log(query); // SELECT * FROM posts ORDER BY `date`
// or
var sorter = 'date';
var query = 'SELECT * FROM posts ORDER BY ' + mysql.escapeId('posts.' + sorter);
console.log(query); // SELECT * FROM posts ORDER BY `posts`.`date`

也可以在 SQL 语句中使用两个问号 ?? 来表示要转义的标识符:

var userId = 1;
var columns = ['username', 'email'];
var query = connection.query('SELECT ?? FROM ?? WHERE id = ?', [columns, 'users', userId], function(err, results) {});

console.log(query.sql); // SELECT `username`, `email` FROM `users` WHERE id = 1

results matching ""

    No results matching ""