NestJS读写查询数据库连接处理及请求连接排查方法
NestJS数据库连接排查与读写分离修正
一、排查请求对应的数据库连接
以下是几种直接有效的排查方式:
1. 给连接添加标识化日志
在数据库连接配置中,为读、写连接分别配置带有名称标识的自定义日志器,让SQL查询日志明确显示所属连接:
// 自定义日志器类 class ConnLogger implements Logger { constructor(private readonly connName: string) {} log(message: string) { console.log(`[${this.connName}] ${message}`); } error(message: string, trace?: string) { console.error(`[${this.connName}] ${message}`, trace); } warn(message: string) { console.warn(`[${this.connName}] ${message}`); } debug(message: string) { console.debug(`[${this.connName}] ${message}`); } verbose(message: string) { console.log(`[${this.connName}] ${message}`); } } // 读连接配置 { name: 'read', type: 'postgres', // 替换为你的数据库类型 host: 'localhost', port: 5432, username: 'read_user', password: 'read_password', database: 'your_db', logging: ['query'], // 仅打印查询日志 logger: new ConnLogger('read'), } // 写连接配置 { name: 'write', type: 'postgres', host: 'localhost', port: 5432, username: 'write_user', password: 'write_password', database: 'your_db', logging: ['query'], logger: new ConnLogger('write'), }
启动项目后,所有SQL查询日志会带上[read]或[write]前缀,直接对应请求使用的连接。
2. 在Service中直接打印连接信息
在处理请求的Service方法里,直接输出当前使用的Repository/Connection的名称:
@Injectable() export class UserService { constructor( @InjectRepository(User, 'read') private readonly userReadRepo: Repository<User>, @InjectRepository(User, 'write') private readonly userWriteRepo: Repository<User>, ) {} async getUsers() { // 打印当前Repository所属连接 console.log(`GET /users 使用连接: ${this.userReadRepo.connection.name}`); return this.userReadRepo.find(); } async createUser(userDto: CreateUserDto) { console.log(`POST /users 使用连接: ${this.userWriteRepo.connection.name}`); return this.userWriteRepo.save(userDto); } }
调用接口后,控制台会直接显示该请求对应的连接名称。
3. 全局拦截器批量检查连接
编写全局拦截器,自动拦截所有请求并记录使用的连接(适用于批量排查):
@Injectable() export class ConnectionCheckInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const request = context.switchToHttp().getRequest(); const controllerName = context.getClass().name; // 从请求上下文获取Service实例(需根据项目结构调整) const targetService = context.getArgByIndex(0); if (targetService) { // 遍历Service属性,检查是否存在Repository/Connection Object.keys(targetService).forEach(key => { const prop = targetService[key]; if (prop?.connection?.name) { console.log(`[${request.method} ${request.path}] Controller: ${controllerName}, 使用连接: ${prop.connection.name}`); } }); } return next.handle(); } }
在main.ts中注册全局拦截器:
async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalInterceptors(new ConnectionCheckInterceptor()); await app.listen(3000); } bootstrap();
二、修正GET请求误用写连接的问题
排查出问题后,通常是以下原因导致的,对应修正即可:
1. 检查Repository注入的连接名
确保GET方法使用的Repository是通过@InjectRepository(Entity, 'read')注入的,而非写连接的'write'标识,避免依赖注入混淆。
2. 确认数据库模块的连接配置
检查TypeOrmModule.forFeature()是否正确关联了对应连接:
@Module({ imports: [ TypeOrmModule.forRootAsync({ name: 'write', useFactory: writeConnFactory }), TypeOrmModule.forRootAsync({ name: 'read', useFactory: readConnFactory }), // 为读连接注册Entity TypeOrmModule.forFeature([User, Post], 'read'), // 为写连接注册Entity TypeOrmModule.forFeature([User, Post], 'write'), ], }) export class DatabaseModule {}
3. 避免连接名拼写错误
检查所有涉及连接名的地方(如@InjectConnection('read')、@InjectRepository(User, 'read')),确保拼写一致,大小写敏感。
内容的提问来源于stack exchange,提问作者mathanu j
相关产品推荐
相关产品推荐

