NodeJS MySQL соединение с несколькими запросами - PullRequest
0 голосов
/ 02 января 2019

Я довольно новичок в NodeJS (из фона PHP).У меня есть базовое понимание асинхронной природы NodeJS по сравнению с блокирующей природой PHP.Я создал несколько приложений Node, которые подключаются к mysql и заставляют их работать.

Мое текущее понимание наилучшего способа выполнения запросов в Node таково:

  • создать пул соединений
  • Когда вам нужно выполнить запрос:
  • getConnection () из пула
  • выполнить запрос
  • .release () connection

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

Итак, я подумал Я мог бы пересмотреть поток соединений:

  • создать пул соединений
  • Когда вам нужно выполнить много запросов:
  • getConnection () из пула
  • итерация по элементам, которые требуют запросов
  • выполнение запросов
  • .release () соединение

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

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

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

Ответы [ 2 ]

0 голосов
/ 03 января 2019

Ваш поток соединения в порядке.Если вы делаете только 1 запрос, вам на самом деле не нужно выполнять никаких шагов, и вы можете просто вызвать .query() в пуле напрямую.(Что делает все остальное под капотом).

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

  • создать соединениепул
  • Когда вам нужно выполнить много запросов:
  • getConnection () из пула
  • запуск транзакции
  • итерация по элементам, которые требуют запросов
  • выполнить запросы
  • в случае сбоя, остановить и откатить
  • , если все выполнено успешно, зафиксировать
  • .release () connection

Youзнать, когда освободить соединение, если все запросы «выполнены».Откуда ты знаешь, что это сделано?Есть несколько способов.Я бы порекомендовал вам использовать API обещаний, поэтому он может выглядеть следующим образом:

async function doStuff(items) {

  try { 
    const connection = await pool.getConnection();
    await connection.beginTransaction();
    for(const item of items) {
      await connection.query('....');
    }
    await connection.commit();
  } catch (e) {
    await connection.rollback();
    throw e;
  } finally {
    await connection.release();
  }

}

У этого шаблона есть несколько преимуществ:

  1. Он будет правильно сообщать об ошибках
  2. Соединение будет разорвано в случае успеха и в случае ошибки.
  3. Оно либо полностью провалится, либо полностью преуспеет.Здесь нет ничего плохого.

Если вам не нужны транзакции, это можно упростить:

async function doStuff(items) {

  try { 
    const connection = await pool.getConnection();
    for(const item of items) {
      await connection.query('....');
    }
  } finally {
    await connection.release();
  }

}

Проблема в том, что вы можете получить частичные успехи,что часто нежелательно, особенно для API.Однако, если он достаточно хорош для вас, он достаточно хорош.

И если вам удобно не иметь транзакций, вы можете теоретически полностью пропустить шаг getConnection:

async function doStuff(items) {
  for(const item of items) {
    await pool.query('....');
  }
}

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

1049 * Как получить обещания включен? 1053 * Ну это немного спорно.Для этого вам может понадобиться переключить пакеты mysql.Существует пакет mysql2 с импортом mysql2/promise, который действительно превосходен (и на самом деле делится кодом с более популярным пакетом mysql).Очень рекомендуется переключиться на это.

Что, если я не хочу переключать пакеты?

Что ж, версия с обратным вызовом намного более болезненная.В этом случае я бы рекомендовал по-прежнему использовать обещания, но преобразовывать ваши обратные вызовы в шаблон обещания, возможно, используя 'promisify'.

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

0 голосов
/ 02 января 2019

Перебор элементов и вставка в базу данных - плохой вариант!Создайте массив объектов в цикле, а затем вставьте все элементы с помощью массовой вставки за один раз.Таким образом, вам нужно вызывать getConnection () только один раз, а затем .release () после массовой вставки.

Если это не так, то в процессе взаимодействия вам нужно вызвать

1) getConnection () 2) выполнить запрос 3) вызвать .release ()

Повторите шаги с 1 по 3 для всех элементов.

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

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