首页 > 代码库 > Node-MySQL 官方文档

Node-MySQL 官方文档

安装

$ npm install mysql


有关之前的0.9.x版本的信息, 请访问 v0.9分支。

有时我还会要求你从Github安装最新版以检查bug是否已修复。在这种情况下,请输入:

$ npm install mysqljs/mysql

 引言

这是node.js的mysql驱动。它是用JavaScript编写的,不需要编译,完全遵循MIT许可协议。

下面是一个如何使用它的例子:

var mysql      = require(‘mysql‘);var connection = mysql.createConnection({  host     : ‘localhost‘,  user     : ‘me‘,  password : ‘secret‘,  database : ‘my_db‘});connection.connect();connection.query(‘SELECT 1 + 1 AS solution‘, function(err, rows, fields) {  if (err) throw err;  console.log(‘The solution is: ‘, rows[0].solution);});connection.end();

 



从这个例子中,你可以了解到以下几点:

    对于一个连接,你所调用的每个方法都是按顺序排队并依次执行的。

    使用end()关闭连接,以确保给mysql服务器发送退出(quit)包以前执行所有剩余的查询。

贡献者

感谢那些给node-mysql模块贡献代码的人们, 参见GitHub 贡献者页面。

另外我还要感谢下面的两个人:

    Andrey Hristov (Oracle) - 帮助我解决了一些协议问题。

    Ulf Wendel (Oracle) -帮助我解决了一些协议问题。

赞助商

下面这些公司给这个项目提供了一些经济支持,请允许我花更多的时间感谢它们(按贡献时间的先后排序):

    Transloadit (项目初期,我们要将文件上传和视频编码做成一个服务,已完成)

    Joyent

    pinkbike.com

    Holiday Extras (他们正在招聘)

    Newscope (他们正在 招聘)

如果你有兴趣赞助一天或更多的时间, 请 与我们联系。
    昌伟兄
昌伟兄
翻译于 4周前

0人顶


 翻译的不错哦!

社区生态

如果你想讨论这个模块的有关问题,亦或是其它的问题,请访问以下的任意一个:

    Mailing list: https://groups.google.com/forum/#!forum/node-mysql

    IRC Channel: #node.js (我关了freenode.net上的mysql的相关信息)

    如何建立链接

        推荐的建立链接的一个方法:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
    
var mysql      = require(‘mysql‘);
var connection = mysql.createConnection({
  host     : ‘example.org‘,
  user     : ‘bob‘,
  password : ‘secret‘
});
connection.connect(function(err) {
  if (err) {
    console.error(‘error connecting: ‘ + err.stack);
    return;
  }
  console.log(‘connected as id ‘ + connection.threadId);
});

然后,我们可以通过建立一个连接来进行查询:
?
1
2
3
4
5
    
var mysql      = require(‘mysql‘);
var connection = mysql.createConnection(...);
connection.query(‘SELECT 1‘, function(err, rows) {
  // connected! (unless `err` is set)
});

以上二种方法都是正确且合适的。至于如何取舍,就要看你怎么去处理所遇到的错误了。不管哪种类型的错误,那都是致命的,我们需要去看所提示的具体的错误信息。

连接参数

在建立新连接时,可以设置以下参数:

    host:连接的数据库地址。(默认:localhost)

    port:连接地址对应的端口。(默认:3306)

    localAddress: 源IP地址使用TCP连接。(可选)

    socketPath:当主机和端口参数被忽略的时候,可以填写一个Unix的Socket地址。

    user: mysql的连接用户名。

    password: 对应用户的密码。

    database: 所需要连接的数据库的名称。(可选)

    charset: 连接的编码形式。这就是mysql中的整理。(例如:utf8_general_ci)如果被指定,则作为默认的整理排序规则。(默认:utf8_general_ci)

    timezone:用来保存当前本地的时区。(默认:local)

    connectTimeout: 设置在连接的时候,超过多久以后未响应则返回失败。(默认:10000)

    stringifyObjects: stringify对象代替转换值。issue# 501。(默认:false)

    insecureAuth:使用旧(不安全)的连接方式去连接MySQL。(默认:false)

    typeCast: 确定列值是否需要转换为本地JavaScript类型。(默认:true)

    queryFormat:自定义查询的方式。地址:Custom format.

    supportBigNumbers: 如果你使用了BIGINT和DECIMAL格式的表列,那么需要开启这个参数来支持。(默认:false)只有当他们超过JavaScript所能表达的最长的字节的时候,如果没有设置这个参数,则会将过长的数字作为字符串传递。否则,返回对象的长度。如果supportBigNumbers参数被忽略,则这个参数也会被忽略。

    dateStrings:一些日期类型(TIMESTAMP, DATETIME, DATE)会以Strings的类型返回,然后转换成JavaScript的日期对象。(默认:false)

    debug:是否把连接情况打印到文件。(默认:false)

    trace: 生成错误的堆栈跟踪,包括库入口的调用位置(“长堆栈的轨迹”)。一般会造成轻微的性能损失。(默认:true)

    秦_Thans
秦_Thans
翻译于 4周前

0人顶


 翻译的不错哦!

终止连接

终止连接的方法有两种。调用end()方法可以正常地终止一个连接:
?
1
2
3
    
connection.end(function(err) {
  // 连接终止
});

这种方法将确保给MySQL服务器发送COM_QUIT包之前所有队列中的查询都会被执行。如果在发送COM_QUIT包之前发生了致命错误,那么会给回调函数传递一个err参数,但是不管怎样连接都会关闭。

另外一种终止连接的方法是调用destroy()方法。该方法会立即终止底层套接字(underlying socket)。另外,destroy()不会触发更多的事件和回调函数。
?
1
    
connection.destroy();

和end()方法不同,destroy()方法不使用回调参数。

连接池连接

直接使用连接池。
?
1
2
3
4
5
6
7
8
9
10
11
12
    
var mysql = require(‘mysql‘);
var pool  = mysql.createPool({
  connectionLimit : 10,
  host            : ‘example.org‘,
  user            : ‘bob‘,
  password        : ‘secret‘,
  database        : ‘my_db‘
});
pool.query(‘SELECT 1 + 1 AS solution‘, function(err, rows, fields) {
  if (err) throw err;
  console.log(‘The solution is: ‘, rows[0].solution);
});

使用连接池连接可以更容易地共享某个连接,也可以管理多个连接。
?
1
2
3
4
5
6
7
8
9
10
    
var mysql = require(‘mysql‘);
var pool  = mysql.createPool({
  host     : ‘example.org‘,
  user     : ‘bob‘,
  password : ‘secret‘,
  database : ‘my_db‘
});
pool.getConnection(function(err, connection) {
  // connected! (unless `err` is set)
});

当连接完成后,调用connection.release()方法使连接返回到连接池,以便其他人可以再次使用。
?
1
2
3
4
5
6
7
8
9
10
    
var mysql = require(‘mysql‘);
var pool  = mysql.createPool(...);
pool.getConnection(function(err, connection) {
  // 使用连接
  connection.query( ‘SELECT something FROM sometable‘, function(err, rows) {
    // 使用连接执行查询
    connection.release();
    //连接不再使用,返回到连接池
  });
});

如果你想关闭连接并从连接池中删除它,就要使用connection.destroy()方法。在下次需要时连接池会再创建一个新的连接。

连接池创建连接很慵懒。如果你配置的连接池最大支持100个连接,但同时只使用了5个连接,那么它只创建5个连接。连接还采用了循环轮转方式,即连接建立在连接池顶部,返回到连接池底部。

当从连接池中恢复之前的某个连接时,会给服务器发送一个ping包以检查连接是否正常。
    昌伟兄
昌伟兄
翻译于 4周前

0人顶


 翻译的不错哦!

连接池的配置参数

连接池接受所有与连接相同的配置参数。创建新连接时,配置参数只是简单的传给连接对象的构造器。除此配置外,连接池还支持一些额外的参数:

    acquireTimeout(获取超时时间): 获取连接时,触发连接超时之前的毫秒数。这与connectTimeout略有不同,因为从连接池获取连接并不总会创建连接 (默认值:10000)

    waitForConnections(连接等待时间):  当无连接可用或连接数达到上限的时候,判定连接池动作。如果为true,连接池会将请求加入队列,待可用之时再触发操作;如为false,连接池将立即返回错误 (默认值:true)   

    connectionLimit(连接数限制): 所允许立即创建的最大连接数量 (默认值: 10)

    queueLimit(队列数量限制): 在调用getConnection返回错误之前,连接池所允许入队列的最大请求数量。如设置为0, 则不限制。 (默认值: 0)

连接池的事件

连接

连接池里面创建了一个新连接时,会触发一个连接事件。如需要在使用此连接之前设置会话变量,将要对此事件进行监听。
?
1
2
3
    
pool.on(‘connection‘, function (connection) {
  connection.query(‘SET SESSION auto_increment_increment=1‘)
});

入列

队列中等待可用连接的回调函数被触发时,连接池将触发此事件。
?
1
2
3
    
pool.on(‘enqueue‘, function () {
  console.log(‘Waiting for available connection slot‘);
});

在连接池中关闭所有连接

如不再需要连接池时,你必须关闭所有连接。否则Node.js脚本的事件流一直处于活跃状态,最终会被MySQL服务器会关闭。脚本占用连接池,这是典型的情况!另外可以以优雅的方式的关闭服务器。关闭所有连接池中的连接,中使用end方法:
?
1
2
3
    
pool.end(function (err) {
  // all connections in the pool have ended
});

end方法接受一个可选的回调函数,以通知(一次)所有已关闭的连接。优雅关闭连接,队列中所有的查询都能被执行,但关闭连接池的时间会不一样。

一旦pool.end()被调用,pool.getConnection及其它操作将不再被执行!
    imqipan
imqipan
翻译于 4周前

0人顶


 翻译的不错哦!

集群连接池

集群连接池提供多主机连接.(分组&重试&选择器)
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
    
// create
var poolCluster = mysql.createPoolCluster();
// add configurations (the config is a pool config object)
poolCluster.add(config); // add configuration with automatic name
poolCluster.add(‘MASTER‘, masterConfig); // add a named configuration
poolCluster.add(‘SLAVE1‘, slave1Config);
poolCluster.add(‘SLAVE2‘, slave2Config);
// remove configurations
poolCluster.remove(‘SLAVE2‘); // By nodeId
poolCluster.remove(‘SLAVE*‘); // By target group : SLAVE1-2
// Target Group : ALL(anonymous, MASTER, SLAVE1-2), Selector : round-robin(default)
poolCluster.getConnection(function (err, connection) {});
// Target Group : MASTER, Selector : round-robin
poolCluster.getConnection(‘MASTER‘, function (err, connection) {});
// Target Group : SLAVE1-2, Selector : order
// If can‘t connect to SLAVE1, return SLAVE2. (remove SLAVE1 in the cluster)
poolCluster.on(‘remove‘, function (nodeId) {
  console.log(‘REMOVED NODE : ‘ + nodeId); // nodeId = SLAVE1
});
poolCluster.getConnection(‘SLAVE*‘, ‘ORDER‘, function (err, connection) {});
// of namespace : of(pattern, selector)
poolCluster.of(‘*‘).getConnection(function (err, connection) {});
var pool = poolCluster.of(‘SLAVE*‘, ‘RANDOM‘);
pool.getConnection(function (err, connection) {});
pool.getConnection(function (err, connection) {});
// close all connections
poolCluster.end(function (err) {
  // all connections in the pool cluster have ended
});

集群连接池选项

    canRetry: 如果为true,当连接失效时,集群连接池将尝试重新连接.  (默认: true)

    removeNodeErrorCount: 如果连接失效,节点的错误次数增加.当错误次数大于removeNodeErrorCount时,该节点从集群链接池中移除 (默认: 5)

    restoreNodeTimeout: 如果连接失效,该参数用于指定尝试获取另一个连接时需要等待的时间,时间单位为毫秒.如果为0,这个节点将被移除并且不会被重复使用.(默认值:0).

    defaultSelector: 默认选择器(默认值:RR)

    RR: 以轮询的方式选择节点. (轮询制)

    RANDOM: 使用随机函数选择节点.

    ORDER: 无条件地选择第一个可用节点.

?
1
2
3
4
5
    
var clusterConfig = {
  removeNodeErrorCount: 1, // Remove the node immediately when connection fails.
  defaultSelector: ‘ORDER‘
};
var poolCluster = mysql.createPoolCluster(clusterConfig);

更换用户并且改变连接状态

MySQL 提供了一个changeUser 命令,该命令允许你在不关闭下列socket的情况下,改变当前用户和连接的其余部分.
?
1
2
3
    
connection.changeUser({user : ‘john‘}, function(err) {
  if (err) throw err;
});

该特性的可用选项有:

    user: 新的用户名 (默认前一次使用的用户名).

    password: 新用户的密码(默认前一次使用的密码).

    charset: 新的字符集 (默认前一次使用的字符集).

    database: 新的数据库名称(默认前一次使用的数据库名).

有时有用的是这个功能的副作用,即会重置任何连接的状态(变量,事物等).

在集群连接池模式下执行changeUser操作如果遇到错误将被视为致命错误.

服务断开连接

由于网络问题、MySQL服务器重启或崩溃,连接超时等问题,你有可能会断开与MySQL服务器的连接.所有上述事件被认定为致命错误,并且将返回错误码‘PROTOCOL_CONNECTION_LOST‘.查看更多信息,请参照错误处理章节.

下一个连接将以建立一个新的连接的方式来获取.当前设计下,一旦终止,现有的一个连接对象将不能够被重连.

连接池状态下,端开的链接将会从连接池中移除并释放空间,下一次调用getConnection时将用释放的空间创建新连接。
    混元归一
混元归一
翻译于 1周前

0人顶


 翻译的不错哦!

执行查询

最基本的执行查询的方法是在一个对象中调用 .query()函数 (比如一个连接或应用池实例)。

最简单的 .query()形式是 .query(sqlString, callback),第一个参数是一条SQL字符串,第二个参数是回调:
?
1
2
3
4
5
    
connection.query(‘SELECT * FROM `books` WHERE `author` = "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)
});

第二个.query()形式是 .query(sqlString, values, callback),带有值的占位符 (查看转义查询值):
?
1
2
3
4
5
    
connection.query(‘SELECT * FROM `books` WHERE `author` = ?‘, [‘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)
});

    第三种 .query()形式是 .query(options, callback),在查询时带有大量的高级可选项,比如 转义查询值(escaping query values),联结重叠列名(joins with overlapping column names),超时(timeouts), 和 类型转换(type casting)。
?
1
2
3
4
5
6
7
8
9
    
connection.query({
  sql: ‘SELECT * FROM `books` WHERE `author` = ?‘,
  timeout: 40000, // 40s
  values: [‘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)
});

注意一种第二和第三形式的结合体也可使用,其中占位符以参数来传递,并且不能做为选项对象。值参数会覆盖选项对象中的值。
?
1
2
3
4
5
6
7
8
9
10
11
    
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)
  }
);
    ZodiacX
ZodiacX
翻译于 4周前

0人顶


 翻译的不错哦!

查询值转义

为了防止SQL注入,每当需要在SQL查询中使用用户数据时,你都应当提前对这些值进行转义。转义可以通过 mysql.escape(), connection.escape() 或 pool.escape() 方法实现:
?
1
2
3
4
5
    
var userId = ‘some user provided value‘;
var sql    = ‘SELECT * FROM users WHERE id = ‘ + connection.escape(userId);
connection.query(sql, function(err, results) {
  // ...
});

另外,也可以使用 ? 作为查询字符串中的占位符,替代你想要转义的值。例如:
?
1
2
3
    
connection.query(‘SELECT * FROM users WHERE id = ?‘, [userId], function(err, results) {
  // ...
});

使用多个占位符则传入的值会依次填入。例如,下方查询中foo将等于a、bar将等于b、baz将等于c,而id将会被赋值为userId的值:
?
1
2
3
    
connection.query(‘UPDATE users SET foo = ?, bar = ?, baz = ? WHERE id = ?‘, [‘a‘, ‘b‘, ‘c‘, userId], function(err, results) {
  // ...
});

这样看起来与MySQL中prepared statements相似,但它内部其实使用了之前的connection.escape() 方法。

注意 它与prepared statements的另一点不同之处是,即使是在注释和字符串中的 ? 也会被替换。

不同类型的值转义的方式是有区别的,其区别如下:

    数字不会被转义

    布尔值会被转移成 true / false

    Date 对象会被转义成形如 ‘YYYY-mm-dd HH:ii:ss‘ 的字符串

    Buffer 会被转义成十六进制字符串,如: X‘0fa5‘

    字符串会被安全地转义

    数组会被转义成列表,例如: [‘a‘, ‘b‘] 会被转义成 ‘a‘, ‘b‘

    嵌套数组会被转义成多个列表(在大规模插入时),如: [[‘a‘, ‘b‘], [‘c‘, ‘d‘]] 会被转义成 (‘a‘, ‘b‘), (‘c‘, ‘d‘)

    对象的所有可遍历属性会被转义成键值对。如果属性的值是函数,则会被忽略;如果属性值是对象,则会使用其 toString() 方法的返回值。

    undefined / null 会被转义成 NULL

    NaN / Infinity 将会被原样传入。由于MySQL 并不支持这些值,在它们得到支持之前,插入这些值将会导致MySQL报错。

如果你足够细心,可能已经注意到了,这种占位符转义可以写出简洁的代码:
?
1
2
3
4
5
    
var post  = {id: 1, title: ‘Hello MySQL‘};
var query = connection.query(‘INSERT INTO posts SET ?‘, post, function(err, result) {
  // Neat!
});
console.log(query.sql); // INSERT INTO posts SET `id` = 1, `title` = ‘Hello MySQL‘

当你觉得有必要亲自对这些查询进行转义时,也可以直接使用转义方法:
?
1
2
    
var query = "SELECT * FROM posts WHERE title=" + mysql.escape("Hello MySQL");
console.log(query); // SELECT * FROM posts WHERE title=‘Hello MySQL‘

查询标识符转义

如果用户提供了不可信的查询标识符(数据库名、表名、列名),你应该用 mysql.escapeId(identifier), connection.escapeId(identifier) 或 pool.escapeId(identifier) 方法对它进行转义,如:
?
1
2
3
4
5
    
var sorter = ‘date‘;
var sql    = ‘SELECT * FROM posts ORDER BY ‘ + connection.escapeId(sorter);
connection.query(sql, function(err, results) {
  // ...
});

同时它还支持限定符,并对限定符两边的内容都进行转义。
?
1
2
3
4
5
    
var sorter = ‘date‘;
var sql    = ‘SELECT * FROM posts ORDER BY ‘ + connection.escapeId(‘posts.‘ + sorter);
connection.query(sql, function(err, results) {
  // ...
});

另外,你还可以用 ?? 作为占位符来替代你想要转义的标识符,如:
?
1
2
3
4
5
6
    
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

请注意,最后这部分的顺序是实验性的,其句法可能在之后的版本中改变。

当你将对象传给 .escape() 或 .query()时,为了防止SQL注入,对象的键将被 .escapeId() 转义。
    twksos
twksos
翻译于 3周前

0人顶


 翻译的不错哦!

预查询

你可以使用 mysql.format 来创建一个多插入点的查询语句,对id和值可以使用适当的转义处理 。下面是一个简单的例子:
?
1
2
3
    
var sql = "SELECT * FROM ?? WHERE ?? = ?";
var inserts = [‘users‘, ‘id‘, userId];
sql = mysql.format(sql, inserts);

这样你就获得了一个有效并且安全的查询语句,然后可以把它发送给数据库。如果你希望在发送给数据库之前就准备好查询语句,这种方法很有用。因为mysql.format是从sqlString.format派生而来的,所以你还可以选择传递stringifyObject 和timezone对象(但不强制要求),并且允许您通过自定义的方式将对象转换成字符串,以及特定地区的时间和时区(location specific/timezone aware Date).
自定义格式

如果你想使用其他样式的转义格式,你可以在连接配置选项中自定义一个自定义的格式函数。如果你还想使用内置的escape()函数或其它的连接函数,可以访问connection对象。
下面是一个实现自定义格式的例子:
?
1
2
3
4
5
6
7
8
9
10
    
connection.config.queryFormat = function (query, values) {
  if (!values) return query;
  return query.replace(/\:(\w+)/g, function (txt, key) {
    if (values.hasOwnProperty(key)) {
      return this.escape(values[key]);
    }
    return txt;
  }.bind(this));
};
connection.query("UPDATE posts SET title = :title", { title: "Hello MySQL" });

获取插入行的id

如果你把一行插入到一个有自增主键的表中,可以这样获得插入的ID:
?
1
2
3
4
    
connection.query(‘INSERT INTO posts SET ?‘, {title: ‘test‘}, function(err, result) {
  if (err) throw err;
  console.log(result.insertId);
});

当处理大数字的时候(超过javascript的Number类型的精度),你需要启用supportBigNumbers选项,以便把插入行的ID作为字符串类型读取出来,否者会抛出一个错误。

当从数据库中查询的数字是一个big number类型的时候,也需要把supportBigNumbers选项设置为true,否则查询出来的数据由于精度限制,会进行四舍五入。
    昌伟兄
昌伟兄
翻译于 3周前

0人顶


 翻译的不错哦!

取得受影响的行数

你可以从 insert,update 或者 delete 子句中取得受影响的行数。
?
1
2
3
4
    
connection.query(‘DELETE FROM posts WHERE title = "wrong"‘, function (err, result) {
  if (err) throw err;
  console.log(‘deleted ‘ + result.affectedRows + ‘ rows‘);
})

取得被改变的行数

你可以从 update 子句取得被改变的行数。

"被改变的行数" 不同于 "受影响行数" ,它不更新行数,而是改变值。
?
1
2
3
4
    
connection.query(‘UPDATE posts SET ...‘, function (err, result) {
  if (err) throw err;
  console.log(‘changed ‘ + result.changedRows + ‘ rows‘);
})

获取连接ID

你可以取得MySQL的连接ID(“线程ID”),这是一个给定的连接,使用的是线程ID属性。
?
1
2
3
4
    
connection.connect(function(err) {
  if (err) throw err;
  console.log(‘connected as id ‘ + connection.threadId);
});

并行执行查询

MySQL协议是顺序的,这意味着你需要多次连接执行并行查询。你可以使用池来管理连接,一个简单的办法是每传入一个http请求,就创建一个连接。
    无若
无若
翻译于 4周前

0人顶


 翻译的不错哦!
其它翻译版本(1)
流式查询行

有的时候可能需要查询大量的数据行,然后在接收到这些数据行的时候一行行的处理它们。就像这样:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    
var query = connection.query(‘SELECT * FROM posts‘);
query
  .on(‘error‘, function(err) {
    // 处理错误,这之后会触发 ‘end‘ 事件
  })
  .on(‘fields‘, function(fields) {
    // 字段信息
  })
  .on(‘result‘, function(row) {
    // 暂停连接。如果你的处理过程涉及到 I/O 操作,这会很有用。
    connection.pause();
    processRow(row, function() {
      connection.resume();
    });
  })
  .on(‘end‘, function() {
    // 所有数据行都已经接收完毕
  });

在上面的示例中,有几点需要注意:

    通常会在接收到一定数量的数据行之后使用 pause() 来暂停连接。这个数量取决于数据行数量和大小。

    pause()/resume() 操作基于套接字和解析器。在调用 pause() 后可以保证不会继续触发 ‘result‘ 事件。

    一定不能给流式查询行的 query() 调用提供回调函数。

    查询到数据行会触发 ‘result‘,INSERT/UPDATE 查询成功的时候也会触发 ‘result‘

    非常重要一点,不要暂停太久,否则会遇到 错误:连接丢失:服务器已断开连接。这个时间限制是在 MySQL 服务器中由 net_write_timeout setting 设置的。

此外,你可能需要知道,目前不可能在流式处理过程中处理单独的行列,它们总是完全缓存的。如果你在 MySQL 方面有流式处理大量字段的经验,希望你能在这里分享。
通过 Streams2 管道输出

查询对象提供了一个便利的方法 .stream([options]) 将查询事件封装在 Readable Streams2 对象中。这个流对象能通过管道简单的流向下游,并基于下游阻塞程度和 highWaterMark 选项自动提供暂停/恢复功能。流对象的 objectMode 参数设置为 true且不可改变(如果你需要一个字节流,那你就得转换流,像示例中的 objstream 那样)。

示例,通过管道将查询结果输出到另一个流(最大缓冲 5 个对象),这很简单:
?
1
2
3
    
connection.query(‘SELECT * FROM posts‘)
  .stream({highWaterMark: 5})
  .pipe(...);
多语句查询

由于安全因素(可能因为不正确的转义造成SQL注入攻击),默认情况下不允许多语句查询。不过可以在连接的时候放开这个限制。
?
1
    
var connection = mysql.createConnection({multipleStatements: true});

一旦设置允许,就可以像执行其它查询那样执行多语句查询:
?
1
2
3
4
5
6
    
connection.query(‘SELECT 1; SELECT 2‘, function(err, results) {
  if (err) throw err;
  // `results` is an array with one element for every statement in the query:
  console.log(results[0]); // [{1: 1}]
  console.log(results[1]); // [{2: 2}]
});

除此之外,也可以流式处理多语句查询的返回结果:
?
1
2
3
4
5
6
7
8
    
var query = connection.query(‘SELECT 1; SELECT 2‘);
query
  .on(‘fields‘, function(fields, index) {
    // the fields for the result rows that follow
  })
  .on(‘result‘, function(row, index) {
    // index refers to the statement this result belongs to (starts at 0)
  });

如果查询中的某一条语句产生错误,则 Error 对象会有一个 err.index 属性用于指出是第几条语句导致的错误。一旦有错误发生,MySQL 会停止执行剩下的语句。

注意,流式处理多语句查询的接口是试验性的,我期待着对它的反馈。
    边城狂人
边城狂人
翻译于 1周前

0人顶


 翻译的不错哦!

存储过程

你可以调用你的存储过程,这来自于你的查询,就像调用任何 mysql 驱动一样。如果存储过程产生多个结果集,作为多个语句查询的结果,它们会以同样的方式暴露在你面前。

join 重叠的列名

当执行 join 操作时,你可以取得类似的结果集来重叠列名。

默认的方式是,node-mysql 将会按顺序覆盖从 MySQL 接收到的重叠列名,这会导致一些接收到的值不可用。

另外,你也可以指定你想要的列,嵌套以下这样的表名:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    
var options = {sql: ‘...‘, nestTables: true};
connection.query(options, function(err, results) {
  /* results will be an array like this now:
  [{
    table1: {
      fieldA: ‘...‘,
      fieldB: ‘...‘,
    },
    table2: {
      fieldA: ‘...‘,
      fieldB: ‘...‘,
    },
  }, ...]
  */
});

或者,使用一个字符串来分隔你合并的结果。
?
1
2
3
4
5
6
7
8
9
10
11
    
var options = {sql: ‘...‘, nestTables: ‘_‘};
connection.query(options, function(err, results) {
  /* results will be an array like this now:
  [{
    table1_fieldA: ‘...‘,
    table1_fieldB: ‘...‘,
    table2_fieldA: ‘...‘,
    table2_fieldB: ‘...‘,
  }, ...]
  */
});

事务

在连接级别,简单事务支持是有效的:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    
connection.beginTransaction(function(err) {
  if (err) { throw err; }
  connection.query(‘INSERT INTO posts SET title=?‘, title, function(err, result) {
    if (err) {
      return connection.rollback(function() {
        throw err;
      });
    }
    var log = ‘Post ‘ + result.insertId + ‘ added‘;
    connection.query(‘INSERT INTO log SET data=http://www.mamicode.com/?‘, log, function(err, result) {
      if (err) {
        return connection.rollback(function() {
          throw err;
        });
      }  
      connection.commit(function(err) {
        if (err) {
          return connection.rollback(function() {
            throw err;
          });
        }
        console.log(‘success!‘);
      });
    });
  });
});

请记住 beginTransaction(), commit() 和 rollback() 是简单方便的函数,这些函数分别执行 START TRANSACTION,COMMIT 和 ROLLBACK 命令。重要的是要理解在 MySQL 中的很多函数所引发的隐含提交,这在MySQL文档中是有相应的描述的。
    无若
无若
翻译于 3周前

0人顶


 翻译的不错哦!

Ping

连接可以使用connection.ping方法向服务器发送一个ping包,若服务器作出响应,将触发回调函数。如果有错误发生,err参数将会传递给回调函数。
?
1
2
3
4
    
connection.ping(function (err) {
  if (err) throw err;
  console.log(‘Server responded to ping‘);
})

超时

每个操作都可以使用一个可选的固定超时(timeout )选项。这样你就可以为操作指定合适的超时时间。要注意的是超时并非MySQL 协议的内容,也不会通过客户端执行,这一点很重要。也就是说,当达到超时时间时,对应的连接将被终止,也不会再执行其它的操作。
?
1
2
3
4
5
6
7
8
9
10
    
// 60秒后终止查询
connection.query({sql: ‘SELECT COUNT(*) AS count FROM big_table‘, timeout: 60000}, function (err, rows) {
  if (err && err.code === ‘PROTOCOL_SEQUENCE_TIMEOUT‘) {
    throw new Error(‘too long to count table rows!‘);
  }
  if (err) {
    throw err;
  }
  console.log(rows[0].count + ‘ rows‘);
});

错误处理

这个模块自带了一种统一的错误处理方法,你必须仔细查看以便写出健壮的应用程序。

该模块创建的大多数错误都是JavaScript的Error对象实例。另外,它们通常还会附带两个额外的属性:

    err.code:  MySQL服务器错误 (比如‘ER_ACCESS_DENIED_ERROR‘), Node.js错误(比如‘ECONNREFUSED‘)或者内部错误(比如‘PROTOCOL_CONNECTION_LOST‘).

    err.fatal: 布尔型, 指出这个错误是否是终端连接对象。 如果错误不是来自MySQL协议操作,那这个属性不被定义。

致命错误会挂起所有的回调。在下面的例子中,试图连接到一个无效端口时触发一个致命错误。因此错误对象传递到了两个回调中:
?
1
2
3
4
5
6
7
8
9
10
11
    
var connection = require(‘mysql‘).createConnection({
  port: 84943, // WRONG PORT
});
connection.connect(function(err) {
  console.log(err.code); // ‘ECONNREFUSED‘
  console.log(err.fatal); // true
});
connection.query(‘SELECT 1‘, function(err) {
  console.log(err.code); // ‘ECONNREFUSED‘
  console.log(err.fatal); // true
});

然而,正常的错误只返回给属于他们的回调函数。所以在下面的例子中,只有第一个回调会接收错误,第二个查询的会出错:
?
1
2
3
4
5
6
7
    
connection.query(‘USE name_of_db_that_does_not_exist‘, function(err, rows) {
  console.log(err.code); // ‘ER_BAD_DB_ERROR‘
});
connection.query(‘SELECT 1‘, function(err, rows) {
  console.log(err); // null
  console.log(rows.length); // 1
});

最后但并非不重要:如果发生了一个致命的错误,但没有一个对应的回调,或者发生了一个正常的错误但没有属于他的回调,那么错误会向连接对象发出‘error‘ 事件。下面的例子说明了这一点:
?
1
2
3
4
    
connection.on(‘error‘, function(err) {
  console.log(err.code); // ‘ER_BAD_DB_ERROR‘
});
connection.query(‘USE name_of_db_that_does_not_exist‘);

注意:error事件在 node中很特殊。如果他们出现而没有绑定侦听器,会打印堆栈跟踪并杀死你的进程。

tl;dr: 这个模块不需要你处理那些静态错误。你总应当给你的方法调用提供回调函数。如果你想忽略这条建议并抑制掉未处理的错误,可以这样做:
?
1
2
    
// I am Chuck Norris:
connection.on(‘error‘, function() {});
    昌伟兄
昌伟兄
翻译于 3周前

0人顶


 翻译的不错哦!

异常(exception)的安全

这个模块是异常(exception)安全的。这意味着你可以持续使用它,它是你的一个回调函数,它会抛出一个错误,你可以使用‘uncaughtException‘或者一个域来捕获它。

类型测试

为了方便起见,这个驱动将会抛出 mysql 类型给本地的 JavaScript 默认类型。存在下面这些映射:

数字型(Number)

    TINYINT

    SMALLINT

    INT

    MEDIUMINT

    YEAR

    FLOAT

    DOUBLE

日期型(Date)

    TIMESTAMP

    DATE

    DATETIME

Buffer类型

    TINYBLOB

    MEDIUMBLOB

    LONGBLOB

    BLOB

    BINARY

    VARBINARY

    BIT (最后一个字节将会填满0)

字符创类型(String)

注意 在二进制字符集合中的文本是作为一个 Buffer 返回的,相当于是一个字符串。

    CHAR

    VARCHAR

    TINYTEXT

    MEDIUMTEXT

    LONGTEXT

    TEXT

    ENUM

    SET

    DECIMAL (可能超出浮点数的精度)

    BIGINT (可能超出浮点数的精度)

    TIME (可以映射成日期型(Date), 但是日期是一个集合?)

    GEOMETRY (从来没使用过,如果你用过请联系我)

不推荐(将来可能消失/改变)关闭类型转换,但是你现在可以做这样的连接:
?
1
    
var connection = require(‘mysql‘).createConnection({typeCast: false});

或者是在查询级别这么做:
?
1
2
3
    
var options = {sql: ‘...‘, typeCast: false};
var query = connection.query(options, function(err, results) {
});

你可以始终通过一个函数来处理类型转换。你可以给定一些列信息,就像数据库,表,类型和长度。如果你想申请自定义类型转换成指定的你可以处理的类型,那么回调函数是默认的。这里举个例子,将 TINYINT(1) 转换成 boolean:
?
1
2
3
4
5
6
7
8
9
    
connection.query({
  sql: ‘...‘,
  typeCast: function (field, next) {
    if (field.type == ‘TINY‘ && field.length == 1) {
      return (field.string() == ‘1‘); // 1 = true, 0 = false
    }
    return next();
  }
});

警告: 在你的自定义类型的回调函数中,你必须调用这三个 field 函数来解析。他们只能被调用一次(查看 讨论 #539)
?
1
2
3
4
5
6
7
    
field.string()
field.buffer()
field.geometry()
are aliases for
parser.parseLengthCodedString()
parser.parseLengthCodedBuffer()
parser.parseGeometryValue()

你可以通过仔细查找,找到 field 函数:

RowDataPacket.prototype._typeCast
    无若
无若
翻译于 3周前

0人顶


 翻译的不错哦!

连接标志

无论何种原因,你要是想改变默认的连接标志,你可以使用连接选项标记。通过逗号分隔字符串,把条目添加到默认的标志中。如果你不想要默认的准备好的标志,你可以用一个负号。添加一个不在默认列表中的标记,仅需要写出标记名称,或者在标记前加一个+号(大小写敏感)。

请记住一些有用的标记,它们是没有被提供的标记(例如:Compression),它们还没有被指定。

例子

下面例子中的黑名单 FOUND_ROWS 标记 来自默认的连接标记。
?
1
    
var connection = mysql.createConnection("mysql://localhost/test?flags=-FOUND_ROWS");

默认标记

下面的标记被发送是通过一个默认的新连接:

    CONNECT_WITH_DB - 指定数据库在连接上的能力。

    FOUND_ROWS - 发送发现affectedRows行而受影响的行。

    IGNORE_SIGPIPE - 老的;无影响。

    IGNORE_SPACE - 让解析器忽略空格之前的(查询。

    LOCAL_FILES - 可以使用 LOAD DATA LOCAL.

    LONG_FLAG

    LONG_PASSWORD - 使用改进的老密码验证版本。

    MULTI_RESULTS - 为 COM_QUERY 可以处理多个结果。

    ODBC Old; 无影响。

    PROTOCOL_41 - 使用4.1协议。

    PS_MULTI_RESULTS - 为 COM_STMT_EXECUTE 可以处理多个结果。

    RESERVED -  4.1 协议的老标记。

    SECURE_CONNECTION - 支持本地4.1认证。

    TRANSACTIONS - 询问事务状态标记。

另外,如果选项 multipleStatements 设置成 true,下面这些将会被发送:

    MULTI_STATEMENTS - 每次查询或者准备声明,客户端都可能会发送多个子句。

其他有用的标记

有其他一些可用的标记。他们可能会也可能不会起作用,但是仍然可用来指定。

    COMPRESS

    INTERACTIVE

    NO_SCHEMA

    PLUGIN_AUTH

    REMEMBER_OPTIONS

    SSL

    SSL_VERIFY_SERVER_CERT

调试和报告问题

如果你遇到问题,你可以在连接时激活调试模式来辅助:
?
1
    
var connection = mysql.createConnection({debug: true});

这将打印所有传入和传出的数据包到 stdout 上。你也可以限制调试包的数组类型,并传递至调试:
?
1
    
var connection = mysql.createConnection({debug: [‘ComQueryPacket‘, ‘RowDataPacket‘]});

限制调试查询和数据包。

如果这篇文章没有帮助到你,你可以打开一个 GitHub 问题。一个好的 GitHub 问题会是这样:

    尽可能减少代码的复制(如果可能的话)

    尽可能调试输出你的环境信息(mysql 版本,node版本,操作系统,等等)尽你的能力去收集。

    无若
无若
翻译于 1周前

0人顶


 翻译的不错哦!

运行测试

测试套件分成两个部分:单元测试和集成测试。单元测试运行在任何机器上,而集成测试需要安装一个MySQL服务器实例。

运行单元测试
?
1
    
$ FILTER=unit npm test

运行集成测试

设置环境变量MYSQL_DATABASE,MYSQL_HOST,MYSQL_PORT,MYSQL_USER 和 MYSQL_PASSWORD。MYSQL_SOCKET 可以被 MYSQL_HOST 和 MYSQL_PORT 替代连接至UNIX socket。之后运行 npm 测试。

举例来说,如果你有一个 mysql 安装被运行在 localhost:3306 并且没有为 root 用户设置密码,运行:
?
1
2
    
$ mysql -u root -e "CREATE DATABASE IF NOT EXISTS node_mysql_test"
$ MYSQL_HOST=localhost MYSQL_PORT=3306 MYSQL_DATABASE=node_mysql_test MYSQL_USER=root MYSQL_PASSWORD= FILTER=integration npm test

那接下来就要做下面这些事:

    预处理子句

    支持的编码格式不止于 UTF-8 / ASCII

Node-MySQL 官方文档