NestJS中TypeORM v0.3.0自定义装饰器如何获取当前数据库连接
NestJS 框架下 TypeORM v0.3+ 外部脚本获取数据库连接方案
TypeORM v0.3 版本彻底移除了getManager()、getConnection()这类全局静态方法,所有数据库连接实例统一由DataSource类管理,原有全局静态查找连接的逻辑失效,才会抛出ConnectionNotFoundError: Connection default was not found错误。
由于class-validator的自定义验证装饰器运行在NestJS依赖注入容器上下文之外,无法直接通过构造器注入获取实例,需要通过持有全局DataSource引用的方式实现访问,具体步骤如下:
步骤1:创建DataSource持有工具
新建一个全局可导入的文件,用来保存初始化完成的DataSource实例,避免重复创建连接:
// src/common/database/datasource.holder.ts import { DataSource } from 'typeorm'; let activeDataSource: DataSource | null = null; /** * 保存初始化完成的DataSource实例,仅在应用启动时调用 */ export const setGlobalDataSource = (ds: DataSource) => { activeDataSource = ds; }; /** * 获取当前活跃的数据库连接实例 */ export const getGlobalDataSource = (): DataSource => { if (!activeDataSource) { throw new Error('DataSource 未完成初始化,请确认应用启动完成后再调用'); } return activeDataSource; };
步骤2:应用启动时存入DataSource实例
两种实现方式选其一即可:
方式A:main.ts启动后赋值(单连接场景推荐)
在Nest应用启动完成后,直接从应用容器取出DataSource实例存入持有器,不需要修改原有TypeORM配置:
// src/main.ts import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { DataSource } from 'typeorm'; import { setGlobalDataSource } from './common/database/datasource.holder'; async function bootstrap() { const app = await NestFactory.create(AppModule); // 从Nest容器取出已经初始化完成的DataSource实例 const dataSource = app.get(DataSource); setGlobalDataSource(dataSource); await app.listen(3000); } bootstrap();
方式B:TypeORM初始化时赋值(多连接场景推荐)
在TypeORM根模块的dataSourceFactory中完成实例赋值,可以精确控制不同连接的持有逻辑:
// src/app.module.ts import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { DataSource } from 'typeorm'; import { setGlobalDataSource } from './common/database/datasource.holder'; @Module({ imports: [ TypeOrmModule.forRootAsync({ useFactory: () => ({ type: 'mysql', // 替换为你实际使用的数据库类型 host: process.env.DB_HOST, port: Number(process.env.DB_PORT), username: process.env.DB_USER, password: process.env.DB_PASS, database: process.env.DB_NAME, entities: [__dirname + '/**/*.entity{.ts,.js}'], synchronize: false, }), dataSourceFactory: async (options) => { const dataSource = await new DataSource(options).initialize(); setGlobalDataSource(dataSource); return dataSource; }, }), ], }) export class AppModule {}
步骤3:验证装饰器中替换原有逻辑
在自定义验证装饰器中,直接导入getGlobalDataSource方法获取实例,替换原有getManager()的写法即可:
import { getGlobalDataSource } from '../common/database/datasource.holder'; // 验证装饰器内部的数据库查询逻辑 const manager = getGlobalDataSource().manager; return manager.count(entity, { ...where, }).then((count) => count < 1);
注意事项
- 不要在应用启动阶段(比如模块加载的顶层代码中)调用
getGlobalDataSource(),此时DataSource还未完成初始化会抛出错误;验证装饰器的逻辑是在请求进入时执行,此时应用已经启动完成,不存在时序问题 - 多数据库连接场景下,可以在持有器中用Map按连接名称存储不同的DataSource实例,按需获取
- 不要手动重复
new DataSource()创建实例,必须使用NestJS TypeORM模块初始化完成的实例,否则会产生多余的数据库连接,造成资源泄漏
内容的提问来源于stack exchange,提问作者Dacxj0
相关产品推荐
相关产品推荐

