Введение
Привет, в этом посте я опишу, как настроить и использовать несколько соединений с базами данных на простом примере.
Документация NestJS по большей части великолепна, но в ней есть некоторые важные упущения в разделе о множественных базах данных.
Я буду исходить из того, что вы уже создали приложение NestJS и настроили 2 или более баз данных и готовы к подключению. Давайте сразу перейдем к делу.
Давайте перейдем к делу
Определите параметры подключения к БД
Следуя документации NestJS, мы найдем пример опций подключения, которые можно задать непосредственно в коде.
...
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: 'root',
database: 'test',
entities: [Customer],
synchronize: true,
}),
],
})
...
Вместо того чтобы выставлять учетные данные непосредственно в коде, мы должны использовать файл конфигурации окружения или аналогичную стратегию.
В данном примере мы воспользуемся пакетом @nestjs/config
для получения учетных данных базы данных из файла окружения. Более подробную информацию о том, как установить и использовать пакет config, можно найти в NestJS Configuration Docs. Это простой процесс.
...
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
}),
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => {
return {
type: 'mssql',
host: configService.get('MAIN_DB_HOST'),
port: parseInt(configService.get('MAIN_DB_PORT')),
database: configService.get('MAIN_DB_DATABASE'),
username: configService.get('MAIN_DB_USERNAME'),
password: configService.get('MAIN_DB_PASSWORD'),
schema: configService.get('MAIN_DB_SCHEMA'),
entities: [Customer],
synchronize: false,
};
},
}),
...
Нам не нужно определять имя соединения для нашего первого соединения. По умолчанию оно будет называться ‘default’ 😬. Для всех остальных определенных соединений нам нужно будет задать имя.
В документации NestJS сказано, что свойство name
должно быть добавлено внутри объекта options, на том же уровне, что и host, port и т.д.
...
@Module({
imports: [
TypeOrmModule.forRoot({
...defaultOptions,
host: 'user_db_host',
entities: [User],
}),
TypeOrmModule.forRoot({
...defaultOptions,
name: 'albumsConnection',
host: 'album_db_host',
entities: [Album],
}),
],
})
...
Теперь, поскольку мы получаем наши учетные данные из файла .env
и используем forRootAsync
, нам нужно добавить свойство connection name
вне функции useFactory
👀. Это действительно важная деталь, которая не упоминается нигде в документации.
Окончательный файл app.module.ts
должен выглядеть следующим образом.
Сущности
Для этого упражнения мы создали две сущности. Сущность Customer будет использовать основное соединение с базой данных, а сущность AccessLog будет использовать вторичное соединение с базой данных. Для получения дополнительной информации о сущностях TypeOrm и шаблоне репозитория ознакомьтесь с NestJS TypeOrm Docs и TypeOrm Docs.
Использование основного подключения к БД
Чтобы получить доступ к функциональности TypeOrm сущности Customer, нам нужно импортировать TypeOrm в модуль Customer.
И вот как мы используем его в сервисе Customer.
Использование вторичного подключения к БД
Как и для основного подключения и сущности Customer, нам нужно импортировать TypeOrm в модуль AccessLog, но на этот раз нам также нужно передать имя подключения в метод TypeOrmModule.forFeature([Entities, ...], connectionName)
.
И вот как мы используем его в службе AccessLog.
Заключение
✅ Нам удалось настроить конфигурацию с несколькими базами данных со значениями учетных данных из файла окружения.
✅ Определили, какое соединение должна использовать каждая сущность.
✅ Зная, как добавить вторичное соединение, мы сможем добавить много других соединений по мере необходимости.
✅ Узнали о небольших проблемах при асинхронной инициализации TypeOrm.
Я очень надеюсь, что эта статья была полезной.
Если у вас есть замечания или вы нашли ошибки, пожалуйста, свяжитесь со мной.