
TypeORM 升级至 v0.3+ 后,getConnectionManager() 和 createConnection() 已被弃用,需改用 DataSource 实现多租户按需连接,并为每个租户隔离 schema。本文详解如何重构旧版逻辑,安全适配新 API。
typeorm 升级至 v0.3+ 后,`getconnectionmanager()` 和 `createconnection()` 已被弃用,需改用 `datasource` 实现多租户按需连接,并为每个租户隔离 schema。本文详解如何重构旧版逻辑,安全适配新 api。
在 TypeORM v0.3+ 中,连接管理模型发生了根本性变化:全局连接管理器(getConnectionManager)被移除,所有连接必须通过显式实例化的 DataSource 对象进行创建与维护。这意味着你不能再依赖单例式的连接池管理,而应采用按需初始化、显式生命周期控制的方式构建多租户连接。
✅ 推荐重构方案:使用 DataSource 替代旧连接逻辑
以下是基于 NestJS 的可复用服务实现,支持动态创建带独立 schema 的租户连接:
// dynamic-db.service.ts
import { Injectable, OnModuleDestroy } from '@nestjs/common';
import { DataSource, DataSourceOptions } from 'typeorm';
import * as tenantsOrmconfig from '../../tenants-orm.config';
@Injectable()
export class DynamicDbService implements OnModuleDestroy {
private readonly connections = new Map<string datasource>();
async createTenantConnection(tenantId: string): Promise<datasource> {
const connectionName = `tenant_${tenantId}`;
// 若已存在且已初始化,直接返回
if (this.connections.has(connectionName)) {
const existing = this.connections.get(connectionName);
if (existing?.isInitialized) return existing;
}
// 构建租户专属配置(注意:schema 字段仍有效,但需确保数据库中已存在)
const baseConfig = tenantsOrmconfig as DataSourceOptions;
const config: DataSourceOptions = {
...baseConfig,
name: connectionName,
schema: connectionName, // ← 仍用于生成表的默认 schema(PostgreSQL)
entities: ['dist/**/*.entity.{ts,js}'],
migrations: ['dist/migrations/*.{ts,js}'],
migrationsRun: true,
migrationsTableName: 'typeorm_migrations',
synchronize: false,
logging: ['error', 'warn', 'info'],
ssl: false,
};
const dataSource = new DataSource(config);
try {
await dataSource.initialize();
this.connections.set(connectionName, dataSource);
console.log(`✅ Tenant connection '${connectionName}' initialized.`);
return dataSource;
} catch (err) {
console.error(`❌ Failed to initialize tenant connection '${connectionName}':`, err);
throw err;
}
}
// 可选:安全关闭连接(建议在应用卸载或租户注销时调用)
async closeTenantConnection(tenantId: string): Promise<void> {
const connectionName = `tenant_${tenantId}`;
const dataSource = this.connections.get(connectionName);
if (dataSource?.isInitialized) {
await dataSource.destroy();
this.connections.delete(connectionName);
console.log(`? Tenant connection '${connectionName}' closed.`);
}
}
onModuleDestroy() {
// 应用关闭时批量清理
for (const [name, ds] of this.connections.entries()) {
if (ds.isInitialized) ds.destroy();
console.log(`? Destroyed tenant connection: ${name}`);
}
this.connections.clear();
}
}</void></datasource></string>
⚠️ 关键注意事项
-
Schema 创建不再自动:TypeORM 不会为你自动创建 PostgreSQL schema。请确保在调用
initialize()前,目标 schema 已存在(可通过 SQLCREATE SCHEMA IF NOT EXISTS tenant_xxx预置,或在 migration 中统一处理)。 -
实体路径需匹配构建输出:
entities和migrations路径须指向编译后的.js文件(如dist/目录),否则运行时将找不到实体类。 -
避免内存泄漏:务必通过
Map缓存并手动管理DataSource实例,防止重复初始化;同时在租户下线或应用退出时调用destroy()。 -
事务与查询作用域:每个
DataSource拥有独立连接池和 QueryRunner,跨租户事务不被支持——这是多租户架构的设计约束,而非缺陷。
? 在 Controller 或 Service 中使用示例
// tenant.service.ts
@Injectable()
export class TenantService {
constructor(private readonly dbService: DynamicDbService) {}
async getTenantRepository<t>(tenantId: string, entity: EntityClassOrSchema<t>) {
const dataSource = await this.dbService.createTenantConnection(tenantId);
return dataSource.getRepository(entity);
}
}
// 使用示例
const repo = await this.tenantService.getTenantRepository('acme', UserEntity);
const users = await repo.find(); // 查询 acme schema 下的 users 表</t></t>
通过以上改造,你不仅能平滑升级到 TypeORM v0.3+,还能获得更清晰的连接生命周期控制、更强的类型安全以及与 NestJS 更自然的集成体验。记住:DataSource 是新标准,拥抱它,而非绕过它。










