2014-09-30 4 views
3
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, я открыл новое соединение каждой операции (запись, GET, PUT, удаление) и отпустите. Это хорошо подходит? или одно соединение лучше? в чем разница между всеми операциями в одном соединении или одним соединением для каждой операции?Node JS (GetConnection)

ответ

3

уточнить - Node.js is не однопоточный. Код приложения выполняется в одном потоке, но под капотом он использует их при необходимости - посмотрите here (как ответ и комментарии ниже него):

В программе Javascript на Node.js есть это только один поток.

Если вы ищете технические возможности, node.js может использовать потоки для решения асинхронного ввода-вывода, если для базовой операционной системы требуется .

И:

Насколько пользователь node.js (то есть программист Javascript) является участие, абстракция, что есть только один поток. В случае случай базовой среды выполнения (v8), он использует потоки внутри для - например, профилирования, и он может делать это свободно, если он не передает эту информацию до Javascript.

Другими словами, если вы погружаетесь в текущую рабочую среду, вы найдете найти более одного потока, помогая сохранить одну нить Javascript работает плавно.

Как вы можете видеть mysql модуль, который вы используете требует передачи обратного вызова для метода query() (и, вероятно, для многих других). Поэтому, когда вы его вызываете, выполнение вашего кода продолжается, и обратный вызов вызывается, когда поступают результаты из базы данных.

Что касается вашего вопроса - вы не создаете новое соединение для каждого запроса.Посмотрите на риого файла mysql модуля, в Pooling Connections section:

Соединение создано отложенно у бассейна. Если вы настроите пул , чтобы разрешить до 100 подключений, но только когда-либо используйте 5 одновременно, будет выполнено только 5 соединений. Соединения также чередуются круговой стиль, при этом соединения берутся из верхней части пула и возвращаются на дно.

Когда предыдущее соединение извлекается из пула, на сервер отправляется пакет ping , чтобы проверить, хорошо ли соединение.

Когда вы вызываете dbPool.getConnection(), соединение создается только в том случае, если в пуле нет доступных подключений - иначе он просто захватывает один из его верхней части. Вызов objConn.release() освобождает соединение обратно в пул - он не отключается. Этот вызов позволяет повторно использовать другие части вашего приложения.

Подводя итог:

  • Создание нового подключения для каждого запроса не является хорошей идеей, как он будет использовать больше ресурсов (CPU, RAM) на обоих вашего приложения и базы данных машин.
  • Использование одного соединения для всех запросов также неверно, потому что, если какая-либо из операций займет много времени, чтобы завершить соединение, встряхните, пока все остальные запросы ожидают его.
  • Использование пула соединений - отличная идея, позволяющая выполнять несколько операций с вашей базой данных одновременно, даже если один из них занимает много времени.

Update: Чтобы ответить на вопросы из комментариев:

При использовании одно соединения для каждого запрос mysql модуля должен открыть новый сокет, подключение к базе данных и аутентификации, прежде чем сделать запрос - это требует времени и ест некоторые ресурсы. Из-за этого это плохой подход.

С другой стороны, при использовании только одного соединения (не пул соединений), выполнение запроса, который занимает много времени, блокирует любые другие запросы по этому соединению до его завершения, что означает, что любой другой запрос придется ждать. Это также плохой подход.

Создание нового пула соединений для каждого запроса в значительной степени напоминает использование нового соединения, если вы не вызываете pool.getConnection() несколько раз - тогда это еще хуже (возьмите ресурсы, используемые при создании нового соединения, и умножьте его на число звонков pool.getConnection()).

Для дальнейшего уточнения одно соединения для каждой операции против всех операций в одном соединении вопроса:

Каждая операция в каждом соединении начинается после того, как предыдущий завершает (это синхронное, но не на клиенте сторона), поэтому, если у вас есть таблица с несколькими миллиардами строк и номер SELECT * FROM yourtable, потребуется некоторое время, чтобы завершить все операции над этим соединением до тех пор, пока оно не закончится.

Если у вас есть одно соединение для каждой операции, которая должна быть выпущена параллельно (например, для каждого запроса), проблема исчезает. Но, как было заявлено ранее, открытие нового соединения требует времени и ресурсов, поэтому была введена пул подключения .

Итак, ответ: используйте один пул соединений для всех запросов (как и в вашем примере кода) - количество подключений будет масштабироваться в соответствии с трафиком вашего приложения.

Update # 2:

Исходя из комментариев, которые я вижу, что я должен объяснить концепцию позади пулов соединений. Как это работает, вы запускаете приложение с пулом соединений пустым и инициализированным, чтобы создать максимум n соединений (по умолчанию он составляет 10 для модуля mysql).

Всякий раз, когда вы вызываете dbPool.getConnection(), он проверяет наличие каких-либо доступных подключений в пуле. Если есть, он захватывает один (делает его недоступным), если он не создает новый. Если достигнут лимит соединения, и нет доступных подключений, возникает какое-то исключение.

Вызов connection.release() освобождает подключение к бассейну, чтобы он был доступен снова.

Использование пула для получения только одного глобального соединения для целого приложения совершенно неверно и против самой концепции (вы можете сделать то же самое, просто создав соединение вручную), поэтому по используйте пул соединений Я имею в виду использовать пул соединений, поскольку он должен был использоваться - чтобы получить от него соединения, когда они вам понадобятся.

+1

Хорошее объяснение. Но вы упустили некоторые важные моменты из вопроса .. (Это хорошее приближение? Или одно соединение лучше? В чем разница между всеми операциями в одном соединении или одним соединением для каждой операции?) –

+0

спасибо за ваше объяснение, но я подумайте, что это не мой вопрос. потому что я тоже использую пул соединений, но я хочу изучить один пул соединений для каждой операции или один пул соединений для каждой операции? is my question – 2014-10-16 09:01:53

+0

@ Naeem-Shaikh хотел (а) уведомлять меня, но не могу редактировать комментарий. – Killah

2

Хорошо, чтобы открыть новое соединение по разным маршрутам. Есть две вещи:

1) Ваша база данных может обрабатывать несколько соединений одновременно.

2) nodejs однопоточный.

Если вы создадите единое соединение для всех маршрутов, вероятно, запрос базы данных, который занимает больше времени для базы данных, также будет голодать на все остальные запросы на узле js server, пока не будет обработан существующий запрос, поскольку существует только одно соединение, совместно используемое приложением.

С другой стороны, если вы используете разные соединения на разных маршрутах, то даже если в базе данных выполняется одна операция блокировки по одному запросу, это не повлияет на другой запрос, поскольку это может сделать совместные соединения с база данных.

+0

Nope, Node.js не является однопоточным. Взгляните на мой ответ ниже. – Killah

+0

Даже если есть несколько потоков, все они просто служат основному потоку. Таким образом, существует только один поток, который может обслуживать клиентов по http в nodejs –

+0

Да, но они все асинхронны - это не PHP. Помните об этом узле.js использует цикл событий - пока вы не выполняете ничего синхронного в коде обработки запроса (и даже если операции базы данных синхронны ** в базе данных **, для узла они все еще асинхронны), это не остановит приложение от обработки большего количества запросов. Здесь не узелое место Node.js - это база данных. – Killah

1

Используя одно соединение каждый раз, неявно управляйте своей транзакцией. Таким образом, результат будет зафиксирован и настолько заметен для других пользователей. Если вы используете одно и то же соединение, вам необходимо зафиксировать его при обновлении, добавлении или удалении, чтобы сделать его видимым для других.

Но, если, например, вы используете цикл для добавления нескольких строк; вы должны рассмотреть возможность использования уникальной транзакции; потому что на стороне сервера db есть накладные расходы для управления контекстом соединения и транзакциями.

Итак, мой ответ: это зависит от того, что вы планируете управлять в своем приложении. Если у вас может быть пакет DML, рассмотрите возможность использования уникального соединения. Кроме того, вы можете использовать несколько соединений.