NestJS TypeORM多连接异常:主连接误用只读副本问题求助
NestJS + TypeORM 多数据库连接异常:主连接更新触发只读副本错误
环境版本
- @nestjs/core: 10.4.15
- @nestjs/typeorm: 10.0.2
配置详情
应用模块配置
@Module({ imports: [ ...getTypeOrmConfig().map(config => TypeOrmModule.forRoot(config)), ] })
双数据库连接配置
export function getTypeOrmConfig(): TypeOrmModuleOptions[] { return [ { name: 'default', // 主库连接 type: 'postgres', host: process.env.TYPEORM_HOST, port: parseInt(process.env.TYPEORM_PORT), username: process.env.TYPEORM_USERNAME, password: process.env.TYPEORM_PASSWORD, database: process.env.TYPEORM_DATABASE, schema: process.env.TYPEORM_SCHEMA, ssl: process.env.TYPEORM_SSL === 'true' ? { rejectUnauthorized: false } : false, entities: ["dist/**/*.entity.js"], logging: process.env.TYPEORM_LOGGING === 'true', synchronize: false, }, { name: 'replica', // 只读副本连接 type: 'postgres', host: process.env.REPLICA_HOST || process.env.TYPEORM_HOST, port: parseInt((process.env.REPLICA_PORT || process.env.TYPEORM_PORT), 10), database: process.env.REPLICA_DATABASE || process.env.TYPEORM_DATABASE, username: process.env.REPLICA_USERNAME || process.env.TYPEORM_USERNAME, password: process.env.REPLICA_PASSWORD || process.env.TYPEORM_PASSWORD, logging: (process.env.REPLICA_LOGGING || process.env.TYPEORM_LOGGING) === 'true', schema: process.env.REPLICA_SCHEMA || process.env.TYPEORM_SCHEMA, ssl: (process.env.REPLICA_SSL || process.env.TYPEORM_SSL) === 'true' ? { rejectUnauthorized: (process.env.REPLICA_SSL_REJECT_UNAUTH || process.env.TYPEORM_SSL_REJECT_UNAUTH) === 'true' } : false, entities: ["dist/**/*.entity.js"], } ]; }
问题表现
明明通过@InjectRepository(InstituteUser, 'default')指定了主库连接的仓库,执行更新操作时却触发只读错误,日志显示操作落到了副本库:
query failed: UPDATE "public"."institute_users" SET "updated_at" = $1 WHERE "id" IN ($2) -- PARAMETERS: ["2025-03-23T08:37:49.000Z",40952] error: cannot execute UPDATE in a read-only transaction
解决办法
1. 明确为每个连接注册实体(根治连接混淆)
问题根源大概率是实体被多个连接共享后,NestJS/TypeORM的依赖注入出现了连接匹配错误。解决方式是为每个连接单独注册实体:
在应用模块中,除了forRoot初始化连接,还要用forFeature为每个连接绑定实体:
@Module({ imports: [ ...getTypeOrmConfig().map(config => TypeOrmModule.forRoot(config)), // 给default主库绑定InstituteUser实体 TypeOrmModule.forFeature([InstituteUser], 'default'), // 给replica副本库绑定实体(如果需要从副本查数据) TypeOrmModule.forFeature([InstituteUser], 'replica'), ] })
这样注入仓库时,就能准确匹配到对应连接的实例。
2. 强制副本库为只读(临时规避误操作)
在副本连接的配置里添加extra参数,强制开启只读事务,就算连接匹配错了也不会触发写操作错误:
{ name: 'replica', // 其他配置不变 extra: { options: '-c default_transaction_read_only=on' } }
这只是临时方案,没法解决连接混淆的根本问题,但能避免业务报错。
3. 调整依赖版本
不少用户反馈这个问题在@nestjs/typeorm的10.0.3+版本或10.0.1版本中被修复了,可以试试:
- 升级到
@nestjs/typeorm@10.0.3及以上 - 或者降级到
@nestjs/typeorm@10.0.1
4. 手动获取连接执行操作
绕过依赖注入,直接从连接管理器拿主库实例来执行更新:
import { ConnectionManager } from 'typeorm'; // 服务中注入ConnectionManager constructor(private connectionManager: ConnectionManager) {} async updateInstituteUser() { const defaultConn = this.connectionManager.get('default'); const repo = defaultConn.getRepository(InstituteUser); await repo.update(/* 更新参数 */); }
这种方式完全绕开了依赖注入的匹配问题,适合紧急修复场景。
内容的提问来源于stack exchange,提问作者Niv Lusty
相关产品推荐
相关产品推荐

