6月5日 00:29

TypeORM多数据库支持:配置差异、MongoDB限制和多数据源方案

TypeORM 的卖点之一是"一套代码跑在多种数据库上"。实际体验下来,SQL 数据库之间迁移确实顺畅,但 MongoDB 是另一回事——文档模型和关系模型的 API 差异很大。这篇文章聚焦实际项目中的数据库选择、配置、以及多数据源场景。

支持的数据库一览

TypeORM 支持的数据库分两类:

SQL 数据库(API 统一,切换成本低):

  • MySQL / MariaDB
  • PostgreSQL
  • SQLite
  • SQL Server
  • Oracle
  • CockroachDB
  • SAP Hana

文档数据库(API 有差异):

  • MongoDB

关键区别:SQL 数据库共享同一套 QueryBuilder API,切换只改 DataSource 配置。MongoDB 不支持 QueryBuilder 的大部分方法,也不支持事务(TypeORM 层面)、关系懒加载等特性。

基础配置

MySQL

typescript
import { DataSource } from 'typeorm'; export const appDataSource = new DataSource({ type: 'mysql', host: process.env.DB_HOST || 'localhost', port: 3306, username: process.env.DB_USER || 'root', password: process.env.DB_PASSWORD, database: process.env.DB_NAME || 'myapp', entities: ['src/entity/*.ts'], synchronize: process.env.NODE_ENV !== 'production', // 生产环境禁止 logging: ['error'], // 只记录错误 SQL });

PostgreSQL

typescript
export const appDataSource = new DataSource({ type: 'postgres', host: process.env.DB_HOST || 'localhost', port: 5432, username: process.env.DB_USER || 'postgres', password: process.env.DB_PASSWORD, database: process.env.DB_NAME || 'myapp', entities: ['src/entity/*.ts'], synchronize: process.env.NODE_ENV !== 'production', // PostgreSQL 特有配置 ssl: process.env.DB_SSL === 'true' ? { rejectUnauthorized: false } : false, schema: 'public', });

MySQL 和 PostgreSQL 的配置几乎一样——改 type 和端口就行。实体代码不需要任何修改。

SQLite(本地开发和测试)

typescript
export const appDataSource = new DataSource({ type: 'sqlite', database: 'data/myapp.db', // 文件数据库 // database: ':memory:', // 内存数据库(测试用) entities: ['src/entity/*.ts'], synchronize: true, });

SQLite 的优势:零配置、零依赖、单文件。适合桌面应用(Electron)、CLI 工具、本地开发。缺点:不支持并发写入、不支持 RETURNING、JSON 函数有限。

MongoDB

typescript
export const appDataSource = new DataSource({ type: 'mongodb', url: process.env.MONGODB_URL || 'mongodb://localhost:27017/myapp', entities: ['src/entity/*.ts'], synchronize: process.env.NODE_ENV !== 'production', // MongoDB 特有配置 authSource: 'admin', replicaSet: 'rs0', // 如果用了副本集 });

MongoDB 的实体定义和 SQL 不同——没有 @Column,用 @ObjectIdColumn@Field

typescript
import { Entity, ObjectIdColumn, ObjectId, Column as Field } from 'typeorm'; @Entity() export class User { @ObjectIdColumn() _id: ObjectId; @Field() name: string; @Field() email: string; @Field(type => [String]) // 数组字段 tags: string[]; }

MongoDB 的限制

  • 不支持 @JoinColumn@ManyToMany 等 SQL 关系装饰器
  • 不支持 QueryBuilder 的 leftJoinsubQuery
  • Repository.find()where 语法不同(用 MongoDB 查询对象)
  • 不支持数据库层面的约束(唯一约束、外键)

数据库选择指南

场景推荐原因
Web 后端 APIPostgreSQL功能最全(JSON、全文搜索、数组、窗口函数)
已有 MySQL 基础设施MySQL不需要额外学习,TypeORM 完全支持
桌面应用(Electron)SQLite零依赖,单文件分发
测试SQLite :memory:最快,每个测试隔离
文档型数据、灵活 schemaMongoDB无需预定义表结构
高并发读 + 简单写MySQL + 读写分离MySQL 主从复制成熟

PostgreSQL 是新项目的默认推荐——JSON 支持、全文搜索、数组类型、窗口函数,比 MySQL 功能丰富很多,而且 TypeORM 的 PostgreSQL 支持最完善。

多数据源配置

一个项目需要连接多个数据库的场景:读写分离(主从)、跨库查询、迁移过渡期。

注册多个 DataSource

typescript
// data-sources.ts export const primaryDataSource = new DataSource({ name: 'primary', // 必须有 name type: 'postgres', host: 'primary-db.example.com', // ... entities: ['src/entity/*.ts'], }); export const secondaryDataSource = new DataSource({ name: 'secondary', // 必须有 name type: 'mysql', host: 'legacy-db.example.com', // ... entities: ['src/entity-legacy/*.ts'], });

NestJS 里使用多数据源

typescript
import { TypeOrmModule } from '@nestjs/typeorm'; @Module({ imports: [ TypeOrmModule.forRoot({ name: 'primary', type: 'postgres', host: 'primary-db.example.com', entities: [User, Post], }), TypeOrmModule.forRoot({ name: 'secondary', type: 'mysql', host: 'legacy-db.example.com', entities: [LegacyUser], }), // 模块指定使用哪个数据源 TypeOrmModule.forFeature([User, Post], 'primary'), TypeOrmModule.forFeature([LegacyUser], 'secondary'), ], }) export class AppModule {}

第二个参数 'primary' / 'secondary' 指定该模块用哪个数据源。不同模块可以用不同数据源。

跨库查询

TypeORM 不支持跨数据源的 JOIN。需要手动查两个库再在代码里合并:

typescript
async function getUserWithLegacy(userId: number) { const user = await primaryDataSource.getRepository(User) .findOne({ where: { id: userId } }); const legacyUser = await secondaryDataSource.getRepository(LegacyUser) .findOne({ where: { email: user.email } }); return { ...user, legacyData: legacyUser }; }

数据库切换和迁移

从 MySQL 切换到 PostgreSQL

  1. 修改 DataSource 配置(type: 'mysql'type: 'postgres'
  2. 检查实体里的 MySQL 特有类型(如 tinyint 改成 boolean
  3. 生成迁移文件:npx typeorm migration:generate -d src/data-source.ts src/migration/InitPg
  4. 跑迁移:npx typeorm migration:run -d src/data-source.ts
  5. 检查 QueryBuilder 里有没有 MySQL 专有语法(如 `backtick` 改成 "double quote"

大部分情况下只需改配置和迁移,实体代码不用动。

synchronize 的正确用法

synchronize: true 在开发时方便——改实体自动同步表结构。但生产环境必须关闭,否则:

  • 删字段时直接 ALTER TABLE DROP COLUMN,数据丢失
  • 重命名字段被当作"删旧列 + 加新列",数据丢失
  • 并发启动多个实例可能同时执行 schema 变更

生产环境用迁移:typeorm migration:run

标签:TypeORM