В официальной документации NestJS есть много примеров, показывающих, как использовать ORM-фреймворк, такой как TypeORM, для интеграции с базой данных. Однако что, если вы не хотите использовать ORM, а предпочитаете выполнять необработанные запросы к базе данных без накладных расходов ORM?
В этом руководстве вы найдете пример того, как это можно сделать. В этом руководстве мы напишем модуль, который будет отвечать за выполнение SQL-запросов в базе данных PostgreSQL.
Обязательные зависимости
Чтобы это работало, нам нужно установить библиотеку, которая позволит нам взаимодействовать с базой данных PostgreSQL. Node-postgres - де-факто стандартная библиотека для этого, так что давайте установим ее:
npm install pg
Поскольку NestJS использует TypeScript, мы также можем установить определения TypeScript для node-postgres:
npm install @types/pg --save-dev
Конфигурационный файл
Конфигурация базы данных обычно хранится во внешнем файле конфигурации, и у вас часто будут разные файлы для разных сред. Для целей этого руководства мы сохраним настройки нашей базы данных в простом .env
файле:
Чтение этого файла не должно быть проблемой, если мы будем использовать встроенный ConfigModule
от NestJS. Мы импортируем этот модуль в наш AppModule
и сделаем его глобальным:
Делать модули глобальными нечасто, если вы действительно не планируете использовать их в большинстве своих прикладных модулей. Чтение конфигурации - обычная задача, поэтому имеет смысл сделать ConfigModule
глобальным. Таким образом, нам не нужно явно импортировать его в каждый модуль приложения. Другое свойство конфигурации, envFilePath
, - это путь к нашему .env
файлу.
Настроив и импортировав ConfigModule
, теперь мы можем использовать ConfigService
во всем приложении для извлечения значений из нашего файла конфигурации. Например, в нашем случае configService.get('POSTGRES_USER')
вернет my-user
.
Модуль базы данных
Теперь давайте создадим специальный модуль, который будет контейнером для нашей функции интеграции с базой данных.
Цель этого модуля - подключиться к базе данных и предоставить службу для выполнения запросов к базе данных.
Рекомендуемый способ подключения к базе данных из приложения NestJS - через пулы баз данных. Пул базы данных - это просто объект node-postgres, который отвечает за управление подключениями к базе данных PostgreSQL.
Поскольку мы будем внедрять этот пул в нашу службу базы данных, мы можем создать его, используя фабричный поставщик. Фабричные поставщики позволяют нам использовать внедрение зависимостей для внедрения других поставщиков, таких как ConfigService
.
В приведенном выше фрагменте мы определили нашего поставщика в массиве providers
модуля, назвали его DATABASE_POOL
и сказали NestJS внедрить экземпляр ConfigService
в нашу фабрику, чтобы мы могли инициализировать объект пула с конфигурацией из нашего .env
файла.
Теперь давайте создадим службу базы данных, которая будет использоваться для выполнения запросов. Метод executeQuery
пока пуст, и мы внедряем объект нашего пула с именем DATABASE_POOL
в службу. Мы также создали экземпляр регистратора NestJS, чтобы мы могли регистрировать запросы к базе данных по мере их возникновения.
Теперь нам нужно экспортировать этот DatabaseService
из нашего DatabaseModule
, чтобы другие модули приложения могли его использовать:
Теперь мы можем закончить executeQuery
method, который будет вызывать pool.query()
для выполнения запросов к базе данных:
Метод прост: он принимает текст запроса, необязательные параметры и возвращает результирующий набор строк.
Наконец: очистка
Пул базы данных, который мы инициализировали в нашем DatabaseModule
, не будет устанавливать никаких подключений, пока не будет выполнен первый запрос. Когда это происходит, создается новый клиент подключения, который сохраняется в пуле, пока пул жив. Если приложение закрывается, этот пул внезапно закрывается без какой-либо очистки.
Чтобы исправить это, мы можем использовать хуки жизненного цикла NestJS и реагировать на сигнал завершения. Прослушивание сигналов завершения действительно потребляет немного больше ресурсов, поэтому это дополнительная функция в NestJS. Его можно включить с помощью метода enableShutdownHooks()
экземпляра приложения.
Включив перехватчики выключения, мы можем записать реальный перехватчик выключения в нашем DatabaseModule
.
Мы используем ссылку на модуль, чтобы получить экземпляр объекта нашего пула из контекста модуля, а затем вызываем его метод end()
для отключения всех активных клиентов. Поскольку этот метод возвращает обещание, NestJS будет ждать в последовательности завершения работы, пока обещание не будет разрешено или отклонено.
Заключение
Спасибо за прочтение. Надеюсь, вы нашли этот урок полезным. Непосредственное взаимодействие с базой данных может быть не таким распространенным вариантом использования в NestJS, но иногда это может быть полезно, когда вам нужен больший контроль над выполняемыми запросами. Если у вас возникнут проблемы, дайте мне знать в комментариях.