Node-MySQL 官方文档 已翻译 100%

oschina 投递于 2016/08/16 11:59 (共 15 段, 翻译完成于 09-05)
阅读 33624
收藏 93
19
加载中

安装

$ 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) -帮助我解决了一些协议问题。

赞助商

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

如果你有兴趣赞助一天或更多的时间, 请 与我们联系

昌伟兄
翻译于 2016/08/16 13:23
3

社区生态

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

        推荐的建立链接的一个方法:

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);
});

然后,我们可以通过建立一个连接来进行查询:

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
翻译于 2016/08/17 09:56
0

终止连接

终止连接的方法有两种。调用end()方法可以正常地终止一个连接:

connection.end(function(err) {
  // 连接终止
});

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

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

connection.destroy();

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

连接池连接

直接使用连接池。

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);
});

使用连接池连接可以更容易地共享某个连接,也可以管理多个连接。

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()方法使连接返回到连接池,以便其他人可以再次使用。

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包以检查连接是否正常。

昌伟兄
翻译于 2016/08/17 13:54
0

连接池的配置参数

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

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

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

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

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

连接池的事件

连接

连接池里面创建了一个新连接时,会触发一个连接事件。如需要在使用此连接之前设置会话变量,将要对此事件进行监听。

pool.on('connection', function (connection) {
  connection.query('SET SESSION auto_increment_increment=1')
});

入列

队列中等待可用连接的回调函数被触发时,连接池将触发此事件。

pool.on('enqueue', function () {
  console.log('Waiting for available connection slot');
});

在连接池中关闭所有连接

如不再需要连接池时,你必须关闭所有连接。否则Node.js脚本的事件流一直处于活跃状态,最终会被MySQL服务器会关闭。脚本占用连接池,这是典型的情况!另外可以以优雅的方式的关闭服务器。关闭所有连接池中的连接,中使用end方法:

pool.end(function (err) {
  // all connections in the pool have ended
});

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

一旦pool.end()被调用,pool.getConnection及其它操作将不再被执行!

imqipan
翻译于 2016/08/17 17:04
1

集群连接池

集群连接池提供多主机连接.(分组&重试&选择器)

// 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: 无条件地选择第一个可用节点.

var clusterConfig = {
  removeNodeErrorCount: 1, // Remove the node immediately when connection fails.
  defaultSelector: 'ORDER'
};
var poolCluster = mysql.createPoolCluster(clusterConfig);

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

MySQL 提供了一个changeUser 命令,该命令允许你在不关闭下列socket的情况下,改变当前用户和连接的其余部分.

connection.changeUser({user : 'john'}, function(err) {
  if (err) throw err;
});

该特性的可用选项有:

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

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

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

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

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

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

服务断开连接

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

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

连接池状态下,端开的链接将会从连接池中移除并释放空间,下一次调用getConnection时将用释放的空间创建新连接。

温安适
翻译于 2016/09/02 15:39
0

执行查询

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

最简单的 .query()形式是 .query(sqlString, callback),第一个参数是一条SQL字符串,第二个参数是回调:

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),带有值的占位符 (查看转义查询值):

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)

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)
});

注意一种第二和第三形式的结合体也可使用,其中占位符以参数来传递,并且不能做为选项对象。值参数会覆盖选项对象中的值。

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)
  }
);
被盗用户
翻译于 2016/08/16 23:58
0

查询值转义

为了防止SQL注入,每当需要在SQL查询中使用用户数据时,你都应当提前对这些值进行转义。转义可以通过 mysql.escape(), connection.escape() 或 pool.escape() 方法实现:

var userId = 'some user provided value';
var sql    = 'SELECT * FROM users WHERE id = ' + connection.escape(userId);
connection.query(sql, function(err, results) {
  // ...
});

另外,也可以使用 ? 作为查询字符串中的占位符,替代你想要转义的值。例如:

connection.query('SELECT * FROM users WHERE id = ?', [userId], function(err, results) {
  // ...
});

使用多个占位符则传入的值会依次填入。例如,下方查询中foo将等于a、bar等于b、baz等于c,而id将会被赋值为userId的值:

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报错。

如果你足够细心,可能已经注意到了,这种占位符转义可以写出简洁的代码:

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'

当你觉得有必要亲自对这些查询进行转义时,也可以直接使用转义方法:

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) 方法对它进行转义,如:

var sorter = 'date';
var sql    = 'SELECT * FROM posts ORDER BY ' + connection.escapeId(sorter);
connection.query(sql, function(err, results) {
  // ...
});

同时它还支持限定符,并对限定符两边的内容都进行转义。

var sorter = 'date';
var sql    = 'SELECT * FROM posts ORDER BY ' + connection.escapeId('posts.' + sorter);
connection.query(sql, function(err, results) {
  // ...
});

另外,你还可以用 ?? 作为占位符来替代你想要转义的标识符,如:

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
翻译于 2016/08/18 14:26
0

预查询

你可以使用 mysql.format 来创建一个多插入点的查询语句,对id和值可以使用适当的转义处理 。下面是一个简单的例子:

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对象。
下面是一个实现自定义格式的例子:

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:

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,否则查询出来的数据由于精度限制,会进行四舍五入。

昌伟兄
翻译于 2016/08/19 13:23
0

取得受影响的行数

你可以从 insert,update 或者 delete 子句中取得受影响的行数。

connection.query('DELETE FROM posts WHERE title = "wrong"', function (err, result) {
  if (err) throw err;
  console.log('deleted ' + result.affectedRows + ' rows');
})

取得被改变的行数

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

"被改变的行数" 不同于 "受影响行数" ,它不更新行数,而是改变值。

connection.query('UPDATE posts SET ...', function (err, result) {
  if (err) throw err;
  console.log('changed ' + result.changedRows + ' rows');
})

获取连接ID

你可以取得MySQL的连接ID(“线程ID”),这是一个给定的连接,使用的是线程ID属性。

connection.connect(function(err) {
  if (err) throw err;
  console.log('connected as id ' + connection.threadId);
});

并行执行查询

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

溪边九节
翻译于 2016/08/17 20:17
1

流式查询行

有的时候可能需要查询大量的数据行,然后在接收到这些数据行的时候一行行的处理它们。就像这样:

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 个对象),这很简单:

connection.query('SELECT * FROM posts')
  .stream({highWaterMark: 5})
  .pipe(...);

多语句查询

由于安全因素(可能因为不正确的转义造成SQL注入攻击),默认情况下不允许多语句查询。不过可以在连接的时候放开这个限制。

var connection = mysql.createConnection({multipleStatements: true});

一旦设置允许,就可以像执行其它查询那样执行多语句查询:

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}]
});

除此之外,也可以流式处理多语句查询的返回结果:

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 会停止执行剩下的语句。

注意,流式处理多语句查询的接口是试验性的,我期待着对它的反馈。

边城
翻译于 2016/09/03 16:17
0
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(12)

s
setfocus

引用来自“vcship”的评论

不错
😄
weineeL
weineeL

引用来自“weineeL”的评论

楼上说的那么多看起来很有道理,因为他不知道node的async和bluebird,各有各的优势。我觉的像phpMyAdmin这种web端管理工具不是只有PHP才能写的出来的。

引用来自“eechen”的评论

说得那么轻巧,那咋不见Java和Node搞一个出来取而代之呢?

引用来自“weineeL”的评论

能不能取而代之不好说, phpMyAdmin 就是一个 web 端的 DB 管理工具而已, PHP 把 php 代码解析成了 HTML, Java 和 nodejs 哪个不能解析动态页面为 HTML?

引用来自“eechen”的评论

说得轻巧,干嘛不写一个出来?能输出HTML的东西是很多,但哪个能有内置模板引擎的PHP那么方便,难道你用Java一行行输出?不行吧,那就得用模板引擎,本质模板引擎还是一行行输出,比如JSP的out.write.

引用来自“快速开发师”的评论

不知道你说的解析是什么意思,但若要生成html 其实是可以的,把jsp的out对象修改成FileOutputStream,让其输出成一个本地html文件,这个out对象本人改过,其实不好改,JSP引擎很多最终类,莫法继承,重写了某些java类勉强实现了
我说的解析是模板转成静态 HTML
快速开发师
快速开发师

引用来自“weineeL”的评论

楼上说的那么多看起来很有道理,因为他不知道node的async和bluebird,各有各的优势。我觉的像phpMyAdmin这种web端管理工具不是只有PHP才能写的出来的。

引用来自“eechen”的评论

说得那么轻巧,那咋不见Java和Node搞一个出来取而代之呢?

引用来自“weineeL”的评论

能不能取而代之不好说, phpMyAdmin 就是一个 web 端的 DB 管理工具而已, PHP 把 php 代码解析成了 HTML, Java 和 nodejs 哪个不能解析动态页面为 HTML?

引用来自“eechen”的评论

说得轻巧,干嘛不写一个出来?能输出HTML的东西是很多,但哪个能有内置模板引擎的PHP那么方便,难道你用Java一行行输出?不行吧,那就得用模板引擎,本质模板引擎还是一行行输出,比如JSP的out.write.
不知道你说的解析是什么意思,但若要生成html 其实是可以的,把jsp的out对象修改成FileOutputStream,让其输出成一个本地html文件,这个out对象本人改过,其实不好改,JSP引擎很多最终类,莫法继承,重写了某些java类勉强实现了
eechen
eechen

引用来自“weineeL”的评论

楼上说的那么多看起来很有道理,因为他不知道node的async和bluebird,各有各的优势。我觉的像phpMyAdmin这种web端管理工具不是只有PHP才能写的出来的。

引用来自“eechen”的评论

说得那么轻巧,那咋不见Java和Node搞一个出来取而代之呢?

引用来自“weineeL”的评论

能不能取而代之不好说, phpMyAdmin 就是一个 web 端的 DB 管理工具而已, PHP 把 php 代码解析成了 HTML, Java 和 nodejs 哪个不能解析动态页面为 HTML?
说得轻巧,干嘛不写一个出来?能输出HTML的东西是很多,但哪个能有内置模板引擎的PHP那么方便,难道你用Java一行行输出?不行吧,那就得用模板引擎,本质模板引擎还是一行行输出,比如JSP的out.write.
weineeL
weineeL

引用来自“weineeL”的评论

楼上说的那么多看起来很有道理,因为他不知道node的async和bluebird,各有各的优势。我觉的像phpMyAdmin这种web端管理工具不是只有PHP才能写的出来的。

引用来自“eechen”的评论

说得那么轻巧,那咋不见Java和Node搞一个出来取而代之呢?
能不能取而代之不好说, phpMyAdmin 就是一个 web 端的 DB 管理工具而已, PHP 把 php 代码解析成了 HTML, Java 和 nodejs 哪个不能解析动态页面为 HTML?
eechen
eechen

引用来自“weineeL”的评论

楼上说的那么多看起来很有道理,因为他不知道node的async和bluebird,各有各的优势。我觉的像phpMyAdmin这种web端管理工具不是只有PHP才能写的出来的。
说得那么轻巧,那咋不见Java和Node搞一个出来取而代之呢?
开源肥牛饭
开源肥牛饭
我次奥这几天我正在用这个东西哈哈哈
weineeL
weineeL
楼上说的那么多看起来很有道理,因为他不知道node的async和bluebird,各有各的优势。我觉的像phpMyAdmin这种web端管理工具不是只有PHP才能写的出来的。
A
AlaDbit
楼上好low nodejs也可以写同步代码呀
eechen
eechen

引用来自“文档信息”的评论

好可怕,php的活被他抢了
好怕哟,说得好像能连MySQL就能取代PHP一样,你以为服务器是浏览器么,只能用你JS.Node赶紧出一个干掉phpMyAdmin的Web管理软件呀. PHP-FPM/MOD_PHP解释完PHP脚本即释放资源,不用担心内存泄露.多进程的实现也完全由PHP-FPM这些C服务实现,也不用担心利用多核实现并发.就这些,你个Node就永远也学不了.况且PHP还有Swoole强势刚你Node正面.一个Node进程里除了一个主线程外,还有JIT线程和GC线程. Node优势在于异步,编程时通过回调的写法把涉及到I/O的操作卸载到事件池,从而避免阻塞到主线程处理下一个请求, 事件池里的事件,处理完成时会自动执行回调函数,响应用户完成请求. 这也意味着,如果你的逻辑涉及到多个I/O操作,那么你就要通过嵌套回调来实现同步顺序执行. 涉及SQL的业务逻辑普遍都是有先后顺序的,要求程序同步顺序执行, 这时Node的异步反而帮倒忙,只能通过嵌套回调来解决. 如果逻辑非常复杂,回调嵌套的层数就可能很多,这时就不利于代码阅读和维护了. 比如连接数据库有一个update更新后select查询的操作, 你就应该把select查询的代码放到update更新操作的回调函数里面去, 处理查询结果并返回给浏览器的代码则需要放到select查询的回调函数里面去.
返回顶部
顶部