Hi I’m Shendi
Nodejs数据库的使用-Mysql
Nodejs专栏
数据库是后端中不可或缺的,而 Nodejs 自然也有与数据库相应的库来使用,Mysql数据库可以使用mysql库
执行以下命令安装 mysql
依赖
npm install mysql
依赖对应的github地址:https://github.com/mysqljs/mysql
通过 requires('mysql')
引入依赖
通过 createConnection
创建连接
示例如下
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : '123456'
});
如果你使用BIGINT,这里需要注意
名称 | 默认值 | 描述 |
---|---|---|
host | localhost | 要连接的数据库的主机名 |
port | 3306 | 连接的端口号 |
localAddress | TCP连接使用的源IP地址(可选) | |
socketPath | 要连接到的unix域套接字的路径。使用时 host 和 port 将被忽略。 | |
user | 进行身份验证的MySQL用户名 | |
password | 该MySQL用户的密码 | |
database | 连接使用的数据库的名称(可选) | |
charset | ‘UTF8_GENERAL_CI’ | 连接的字符集。这在MySQL的SQL级别中被称为“排序规则”(如utf8_general_ci)。如果指定了SQL级别的字符集(如utf8mb4),则使用该字符集的默认排序规则 |
timezone | ‘local’ | MySQL服务器上配置的时区。这用于将服务器日期/时间值强制转换为JavaScriptDate对象,反之亦然。这可以是“local”、“Z”或形式为+HH:MM或-HH:MM的偏移量 |
connectTimeout | 10000 | 初始连接到MySQL服务器之前的超时毫秒数 |
stringifyObjects | false | 将对象转换为字符串,而不是转换为值 |
insecureAuth | false | 允许连接到要求使用旧(不安全)身份验证方法的MySQL实例 |
typeCast | true | 确定是否应将列值转换为原生的JavaScript类型 |
queryFormat | 自定义查询格式函数。参见Custom format。 | |
supportBigNumbers | false | 在数据库中处理大数字(BIGINT和DECIMAL列)时,应启用此选项 |
bigNumberStrings | false | 如果同时启用 supportBigNumbers 和 bigNumberStrings ,则强制将大数字(BIGINT 和 DECIMAL 列)作为 JavaScript String 对象返回。启用supportBigNumbers,但禁用bigNumberStrings,只有当它们不能用[JavaScriptNumberobjects]准确表示时,才会将大数字作为String对象返回(https://tc39.es/ecma262/#sec-ecmascript语言类型为数字类型)(当它们超过[-253,+253]范围时会发生这种情况),否则它们将作为number对象返回。如果禁用supportBigNumbers,则会忽略此选项。 |
dateStrings | false | 强制将日期类型(TIMESTAMP、DATETIME、DATE)作为字符串返回,而不是膨胀为 JavaScript Date 对象。可以是 true/false 或保留为字符串的类型的数组 |
debug | false | 将协议详情打印到 stdout。可以是 true/false 也可以是应该打印的数据包类型名称的数组 |
trace | true | 在 Error 上生成堆栈跟踪,包括库入口的调用现场(“长堆栈跟踪”)。大多数调用会有轻微的性能损失 |
localInfile | true | 允许 LOAD DATA INFILE 使用 LOCAL修饰符 |
multipleStatements | false | 允许每个query使用多个 mysql 语句。小心使用此功能,它可能会增加 SQL注入攻击的范围 |
flags | 除默认值之外的其他连接标志列表。也可以使用黑名单禁用默认标志。有关更多信息,请查看连接标志。 | |
ssl | 具有 ssl 参数的对象或包含 ssl 配置文件名的字符串。 |
除了上面这种传递对象参数的方式,还可以直接通过字符串创建
var connection = mysql.createConnection('mysql://user:pass@host/db?debug=true&charset=BIG5_CHINESE_CI&timezone=-0700');
通过 connect
进行连接
connection.connect(function(err) {
if (err) {
console.error('连接失败: ' + err.stack);
return;
}
console.log('连接成功,id ' + connection.threadId);
});
connection.query('SELECT 1', function (error, results, fields) {
if (error) throw error;
// connected!
});
当然,直接使用 query 也可以隐式进行连接
connection.query('SELECT 1', function (error, results, fields) {
if (error) throw error;
// connected!
});
该模块提供了内置的连接池,而不是逐个创建和管理连接
直接使用连接池的方式,这样就不需要关心连接问题
通过 createPool
创建连接池
示例如下
var mysql = require('mysql');
var pool = mysql.createPool({
connectionLimit : 10,
host : 'sdpro.top',
user : 'Shendi',
password : '123456',
database : 'db'
});
pool.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
if (error) throw error;
console.log('The solution is: ', results[0].solution);
});
直接使用 pool 进行操作可能每次使用的连接都不一样,有的时候会需要同一个连接执行多个语句,例如事务,这时可以通过 getConnection
来从连接池获取一条连接
示例如下
var mysql = require('mysql');
var pool = mysql.createPool(...);
pool.getConnection(function(err, connection) {
// 没有连接
if (err) throw err;
// 使用连接
connection.query('SELECT something FROM sometable', function (error, results, fields) {
// 操作完后将连接释放(回归连接池)
connection.release();
// Handle error after the release.
if (error) throw error;
// Don't use the connection here, it has been returned to the pool.
});
});
如果您想关闭连接并将其从池中删除则使用 connection.destroy()
在创建连接池时候传递的Obj选项,连接池拥有连接的所有选项,除此之外,还有以下选项
名称 | 默认值 | 描述 |
---|---|---|
acquireTimeout | 10000 | 连接获取过程中发生超时前的毫秒数。这与connectTimeout略有不同,因为获取池连接并不总是涉及建立连接。如果连接请求已排队,则该请求在队列中花费的时间不计入此超时 |
waitForConnections | true | 确定当没有可用连接并且已达到限制时池的操作。如果为true,则池将对连接请求进行排队,并在连接请求可用时调用它。如果为false,则池将立即回调并返回错误 |
connectionLimit | 10 | 一次创建的最大连接数 |
queueLimit | 0 | 池在从getConnection返回错误之前可以排队的最大连接请求数。如果设置为0,则对排队的连接请求没有限制 |
当从池中获取连接时,池将发出“获取”事件。这是在连接上执行了所有获取活动之后调用的,就在连接被移交给获取代码的回调之前
pool.on('acquire', function (connection) {
console.log('Connection %d acquired', connection.threadId);
});
当在池中建立新连接时,池将发出“连接”事件。如果在使用连接之前需要在连接上设置会话变量,则可以侦听“connection”事件
pool.on('connection', function (connection) {
connection.query('SET SESSION auto_increment_increment=1')
});
当回调已排队等待可用连接时,池将发出“入队”事件。
pool.on('enqueue', function () {
console.log('Waiting for available connection slot');
});
当连接释放回池时,池将发出“释放”事件。这是在对连接执行了所有发布活动之后调用的,因此在事件发生时,连接将被列为空闲
pool.on('release', function (connection) {
console.log('Connection %d released', connection.threadId);
});
不管增删改查都是使用 query
执行query的最基本方法是对对象(如Connection、Pool或PoolNamespace实例)调用 query
方法
query 最简单的形式是 query(sqlString, callback),其中sqlString是sql语句,callback是回调函数
connection.query('SELECT * FROM `books` WHERE `author` = "David"', function (error, results, fields) {
// error发生错误则为Error
// results是查询的结果
// fields是返回的结果字段信息(如果有)
});
第二种形式,像预编译,但实际上它只是在内部使用相同的connection.eescape 方法。防sql注入(在这里称为转义,查阅 escaping query values)
query(sqlString, values, callback)
其中 values 是参数列表,例如
connection.query('SELECT * FROM `books` WHERE `author` = ?', ['David'], function (error, results, fields) {
});
也可以像下面这样
connection.query({
sql: 'SELECT * FROM `books` WHERE `author` = ?',
timeout: 40000, // 40s
values: ['David']
}, function (error, results, fields) {
});
connection.query({
sql: 'SELECT * FROM `books` WHERE `author` = ?',
timeout: 40000, // 40s
},
['David'],
function (error, results, fields) {
// error will be an Error if one occurred during the query
// results will contain the results of the query
// fields will contain information about the returned results fields (if any)
}
);
// 如果查询只有一个替换字符(?),并且该值不是null、未定义或数组,则可以将其作为第二个参数直接传递给.query
connection.query(
'SELECT * FROM `books` WHERE `author` = ?',
'David',
function (error, results, fields) {
}
);
使用连接的 beginTransaction
开启事务,接收一个回调函数,需要手动对连接进行回滚(rollback)或提交(commit)
示例如下
connection.beginTransaction(function(err) {
if (err) { throw err; }
connection.query('INSERT INTO posts SET title=?', title, function (error, results, fields) {
if (error) {
return connection.rollback(function() {
throw error;
});
}
var log = 'Post ' + results.insertId + ' added';
connection.query('INSERT INTO log SET data=?', log, function (error, results, fields) {
if (error) {
return connection.rollback(function() {
throw error;
});
}
connection.commit(function(err) {
if (err) {
return connection.rollback(function() {
throw err;
});
}
console.log('success!');
});
});
});
});
我封装的工具类如下
var mysql = require('mysql');
/**
* Sql工具类
* @authro 砷碲
*/
class SqlUtil {
/** 连接池 */
static pool = mysql.createPool({
host : 'localhost',
port : 3306,
user : 'root',
password : 'pwd',
database : 'db',
supportBigNumbers : true,
multipleStatements : true,
connectionLimit : 5,
});
/**
* 执行sql语句. Promise.
* 示例
* exec("SELECT * FROM xx WHERE id=?", [1]).then((results,fields) => {
* console.log(results, fields);
* }).catch((err) => {
* console.error("查询失败:", err);
* });
* @param {any} obj sql字符串或者参数对象,
* @param {Array} escaping 转义列表,对应sql字符串的问号,可选
*/
static exec(obj, escaping) {
return new Promise((resolve, reject) => {
if (typeof obj == 'string') obj = { sql: obj };
if (escaping) obj.values = escaping;
SqlUtil.pool.query(obj, function (error, results, fields) {
if (error) {
reject(error);
} else {
resolve(results, fields);
}
});
});
}
}
module.exports=SqlUtil;
将其挂载到全局,所有js可用
global.SqlUtil = require("./SqlUtil");
END