节点js(getConnection)

var nodePort = 3030; var express = require('express'); var app = express(); var bodyParser = require('body-parser'); var db = require('mysql'); var dbPool = db.createPool({ host : 'localhost', user : 'root', password : '1234', database : 'test', port : 3306 }); app.use( bodyParser.json() ); app.get('/api/db', function(req, res){ res.setHeader('content-type', 'application/json'); dbPool.getConnection(function(objErr, objConn){ if(objErr){ sendError(res, 503, 'error', 'connection', objErr); //503 - Service Unavailable }else{ objConn.query("SELECT * FROM person", function(Err, Rows, Fields){ if(Err){ sendError(res, 500, 'error', 'query', Err); }else{ res.send({ results : 'success', err : '', err_type : '', fields : Fields, rows : Rows, length : Rows.length }); objConn.release(); }//else }); }//else }); }); /* app.get('/api/db:id', function(req, res){ var id = req.params.id; res.setHeader('content-type', 'application/json'); dbPool.getConnection(function(objErr, objConn){ if(objErr){ sendError(res, 503, 'error', 'connection', objErr); //503 - Service Unavailable }else{ objConn.query("SELECT * FROM person WHERE id = ? ",[id], function(Err, Rows, Fields){ if(Err){ sendError(res, 500, 'error', 'query', Err); }else{ res.send({ results : 'success', err : '', err_type : '', fields : Fields, rows : Rows, length : Rows.length }); objConn.release(); }//else }); }//else }); }); */ app.post('/api/db', function(req, res){ if(!req.body.tableName){ var data = { ID : req.body.id, Name : req.body.name } tableName = 'person'; }else{ var data = { email : req.body.email, regid : req.body.regid } tableName = 'users'; }//else console.log(req.body.regid); console.log(req.body.tableName); console.log(req.body.email); res.setHeader('content-type', 'application/json'); dbPool.getConnection(function(objErr, objConn){ if(objErr){ sendError(res, 503, 'error', 'connection', objErr); //503 - Service Unavailable }else{ objConn.query("INSERT INTO "+tableName+" SET ? ", data, function(Err, Rows, Fields){ if(Err){ sendError(res, 500, 'error', 'query', Err); }else{ res.send({ results : 'success' }); objConn.release(); if(!req.body.tableName){ gcmSend(); } }//else }); }//else }); }); app.put('/api/db', function(req, res){ var id = req.body.id; var data = { Name : req.body.name } res.setHeader('content-type', 'application/json'); dbPool.getConnection(function(objErr, objConn){ if(objErr){ sendError(res, 503, 'error', 'connection', objErr); //503 - Service Unavailable }else{ objConn.query("UPDATE person SET ? WHERE ID = ? ", [data,id], function(Err, Rows, Fields){ if(Err){ sendError(res, 500, 'error', 'query', Err); }else{ res.send({ results : 'success' }); objConn.release(); gcmSend(); }//else }); }//else }); }); app.delete('/api/db/:id', function(req, res){ var id = req.params.id; res.setHeader('content-type', 'application/json'); dbPool.getConnection(function(objErr, objConn){ if(objErr){ sendError(res, 503, 'error', 'connection', objErr); //503 - Service Unavailable }else{ objConn.query("DELETE FROM person WHERE ID = ? ",[id], function(Err, Rows, Fields){ if(Err){ sendError(res, 500, 'error', 'query', Err); }else{ res.send({ results : 'success' }); objConn.release(); gcmSend(); }//else }); }//else }); }); function gcmSend(){ message = new gcm.Message({ collapseKey: 'demo', delayWhileIdle: true, timeToLive: 3, data: { title: 'Node.js den mesaj gönderildi' } }); sender.send(message, registrationIds, 4, function (err, result) { console.log(result); }); } function sendError(res, iStatusCode, strResult, strType, objError){ res.send({ results : strResult, err : objError.type, err_type : strType }); } app.listen(nodePort); console.log('App listening on port' + nodePort); 

嗨,
我写了一些代码来连接nodejs mysql,我打开了新的连接,每个操作(post,get,put,delete)和release。 这很好吗? 或者一个连接更好? 一个连接中的所有操作或每个操作的一个连接之间有什么区别?

澄清 – Node.js 不是单线程的。 你的应用程序代码是在一个线程中执行的,但是在需要的时候使用它们 – 看看这里 (答案和下面的注释):

对于node.js上的Javascript程序,只有一个线程。

如果您正在寻找技术,node.js可以自由使用线程来解决asynchronousI / O,如果底层操作系统需要它。

和:

就node.js(即Javascript程序员)的用户而言,抽象是只有一个线程。 在底层运行时(v8)的情况下,它在内部使用线程进行分析,并且可以自由地进行操作,只要它不泄漏信息到Javascript即可。

换句话说,如果你在实际的运行时间内下潜,你会发现有多个线程可以帮助单个Javascript线程顺利运行。

正如你所看到的你使用的mysql模块要求你传递一个query()方法的callback(可能还有更多)。 所以当你调用它的时候,代码的执行会继续,当数据库到达时调用callback函数。

至于你的问题 – 你没有为每个请求创build一个新的连接。 查看一下mysql模块的自述文件Pooling Connections部分 :

连接是由游泳池懒洋洋地创build的。 如果将池configuration为允许多达100个连接,但只能同时使用5个连接,则只能build立5个连接。 连接也是循环式循环,连接从池的顶部被取出并返回到底部。

当从池中检索到以前的连接时,会将ping数据包发送到服务器以检查连接是否仍然正常。

当调用dbPool.getConnection() ,只有在池中没有更多可用连接的情况下才会创build连接,否则它只会从顶端抓取一个连接。 调用objConn.release()将连接释放回池 – 它没有被断开连接。 这个调用允许它被应用程序的其他部分重用。

总结一下:

  • 为每个请求创build新的连接并不是一个好主意,因为它将在应用程序和数据库的机器上使用更多的资源(CPU,RAM)。
  • 对所有请求使用一个连接也是错误的,因为如果任何操作需要很长时间才能完成连接,则会挂起所有其他请求等待它。
  • 使用连接池是一个好主意,它允许您同时对数据库执行多个操作,即使其中一个操作需要很长时间才能完成。

更新:回答评论的问题:

当你为每个请求使用一个连接时, mysql模块必须打开一个新的套接字,连接到数据库并进行身份validation,然后才能进行查询 – 这需要时间并消耗一些资源。 因为这是一个坏的方法。

另一方面,当只使用一个连接 (而不是连接池)时,运行一个需要很长时间才能完成的查询将阻塞该连接上的任何其他查询,直到它完成 – 这意味着任何其他请求将不得不等待。 这也是一个坏方法。

为每个请求创build一个新的连接池就像使用新的连接一样,除非多次调用pool.getConnection() – 然后更糟糕的是(创build一个新的连接所使用的资源并将其乘以pool.getConnection()的数量pool.getConnection()调用)。

为了进一步明确每个操作一个连接一个连接问题中的所有操作

每个连接中的每个操作在前一个连接完成后(它是同步的,而不是在客户端)开始,所以如果你有一个有几十亿行的表并且发出SELECT * FROM yourtable ,则需要一些时间才能完成,这个连接上的每一个操作,直到完成。

如果每个操作需要并行发出一个连接(例如,针对每个请求),问题就会消失。 但是如前所述,开放一个新的连接需要时间和资源,这就是连接池概念引入的原因。

所以答案是: 对所有请求使用一个连接池 (就像在示例代码中那样) – 连接数量将根据应用程序的stream量进行相应调整。

更新#2:

根据评论我看到,我也应该解释连接池背后的概念。 它是如何工作的,你启动一个连接池为空的应用程序,并初始化,以创build最多n个连接(afaik默认为mysql模块为10)。

无论何时调用dbPool.getConnection()都会检查池中是否有可用的连接。 如果有它抓住一个(使其不可用),否则它创build一个新的。 如果达到连接限制并且没有可用的连接,则引发某种exception。

调用connection.release()将连接释放回池中,使其再次可用。

使用一个池来获取整个应用程序只有一个全局连接是完全错误的,违背了概念本身(你可以通过手动创build连接来做同样的事情),所以通过使用连接池,我的意思是使用连接池本来应该被使用的 – 当你需要的时候可以从中获得连接

在不同的路线上打开一个新的连接是很好的。 有两件事,

1)你的数据库可以同时处理多个连接。

2)nodejs是单线程的。

如果为所有路由创build单个连接,那么对于数据库来说需要更长时间的数据库请求也可能会使节点js服务器上的所有其他请求挨饿,直到处理现有请求为止,因为应用程序只有一个连接共享。

另一方面,如果在不同的路由上使用不同的连接,那么即使单个请求对数据库执行阻塞操作,也不会影响其他请求,因为它可以与数据库进行严格的连接。

每次使用一个连接,隐式地pipe理你的事务。 所以结果将被提交并对其他用户可见。 如果您使用相同的连接,则必须在更新,添加或删除时进行提交,以使其他人可见。

但是,如果你使用一个循环来添加很多行, 你应该考虑使用一个独特的交易; 因为在数据库服务器端有pipe理连接上下文和事务的开销。

所以我的答案是:这取决于你计划在你的应用程序中pipe理什么。 如果您可能有一批DML,请考虑使用独特的连接。 否则你可能会使用多个连接。