Javascript 节点js(getConnection)
嗨,Javascript 节点js(getConnection),javascript,mysql,node.js,Javascript,Mysql,Node.js,嗨, 我写了一些代码来连接nodejs-mysql,我在每次操作(post、get、put、delete)和发布时都打开了新的连接。这样好吗?还是一个连接更好?一个连接中的所有操作或每个操作的一个连接之间有什么区别?最好在不同的路由上打开一个新连接。 有两件事, 1) 您的数据库可以同时处理多个连接 2) nodejs是单线程的 如果为所有路由创建一个连接,则数据库请求很可能会占用更长的时间,在处理现有请求之前,该数据库请求也会耗尽node js server上的所有其他请求,因为应用程序只共
我写了一些代码来连接nodejs-mysql,我在每次操作(post、get、put、delete)和发布时都打开了新的连接。这样好吗?还是一个连接更好?一个连接中的所有操作或每个操作的一个连接之间有什么区别?最好在不同的路由上打开一个新连接。 有两件事, 1) 您的数据库可以同时处理多个连接 2) nodejs是单线程的 如果为所有路由创建一个连接,则数据库请求很可能会占用更长的时间,在处理现有请求之前,该数据库请求也会耗尽node js server上的所有其他请求,因为应用程序只共享一个连接
另一方面,如果您在不同的路由上使用不同的连接,那么即使单个请求正在数据库上执行阻塞操作,这也不会影响其他请求,因为它可以创建到数据库的saperate连接。为了澄清-Node.js是而不是单线程的。您的应用程序代码在一个线程中执行,但在需要时,它会在后台使用它们—请看一看(答案和下面的注释): 对于node.js上的Javascript程序,只有一个线程 如果您想了解技术细节,node.js可以自由使用线程 在底层操作系统需要时解决异步I/O 它 以及: 就node.js的用户(即Javascript程序员)而言 涉及的抽象是只有一个线程。在里面 对于底层运行时(v8),它在内部使用线程 例如,分析,它可以自由地这样做,只要 不会将该信息泄露给Javascript 换句话说,如果深入实际运行时,您将 找到多个线程来帮助保持单个Javascript线程 运行平稳 如您所见,您使用的
mysql
模块要求您为query()
方法(可能还有更多)传递回调。因此,当您调用它时,代码的执行将继续,当来自数据库的结果到达时,将调用回调
至于你的问题,你不是在为每个请求创建一个新的连接。请看一下mysql
模块的自述文件,其中包括:
连接是由池延迟创建的。如果您配置了池
允许最多100个连接,但只能同时使用5个,
仅进行5次连接。连接也会循环
循环式,连接从顶部开始
然后回到池底
当从池中检索到上一个连接时,ping数据包
发送到服务器以检查连接是否仍然良好
调用dbPool.getConnection()
时,仅当池中没有其他可用连接时才会创建连接,否则它只会从池的顶部获取一个连接。调用objConn.release()。此调用允许应用程序的其他部分重用它
总而言之:
- 为每个请求创建新连接不是一个好主意,因为它会在应用程序和数据库的机器上使用更多的资源(CPU、RAM)
- 对所有请求使用一个连接也是错误的,因为如果任何操作需要很长时间才能完成,您的连接将挂起,使所有其他请求等待它
- 使用连接池是一个好主意,它允许您同时对数据库执行多个操作,即使其中一个操作需要很长时间才能完成
更新:
回答评论中的问题:
当您对每个请求使用一个连接时,mysql
模块必须打开一个新套接字,连接到数据库并进行身份验证,然后才能进行查询-这需要时间并消耗一些资源。正因为如此,这是一个糟糕的方法
另一方面,当只使用一个连接(不是连接池)时,运行一个需要很长时间才能完成的查询将阻止该连接上的任何其他查询,直到它完成为止,这意味着任何其他请求都必须等待。这也是一个糟糕的方法
为每个请求创建一个新的连接池与使用新连接非常相似,除非您多次调用pool.getConnection()
,否则情况更糟(将创建新连接所使用的资源乘以pool.getConnection()
调用的次数)
要进一步澄清每个操作的一个连接与一个连接问题中的所有操作:
每个连接中的每个操作都是在前一个操作完成后启动的(它是同步的,但不在客户端),因此如果您有一个包含几十亿行的表,并发出SELECT*FROM yourtable
则需要一些时间来完成,阻塞此连接上的每个操作,直到完成为止
如果每个操作都有一个需要并行发出的连接(例如每个请求),那么问题就会消失。但是如前所述,打开一个新连接需要时间和资源,这就是为什么引入了连接池概念
因此答案是:对所有请求使用一个连接池(就像您在示例代码中所做的那样)——连接数量将根据应用程序上的流量进行相应的缩放
更新#2:
根据我看到的评论,我还应该解释连接池背后的概念。它的工作原理是在连接池为空的情况下启动应用程序,并初始化以创建最多n个连接
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);