首页
/ TypeORM DataSource 完全指南:创建、初始化与数据库连接的工程实践

TypeORM DataSource 完全指南:创建、初始化与数据库连接的工程实践

2026-09-05 22:52:00作者:冯爽妲Honey

在 TypeORM 中,DataSource 是所有数据库操作的唯一入口:它承载连接配置、建立数据库连接或连接池,并通过 initialize / destroy 两个方法掌控整个连接生命周期。本文基于仓库文档 1-data-source.md,结合 DataSource 核心实现驱动工厂官方配置样例,讲解如何创建、初始化和使用 DataSource,并深入其构造与连接建立阶段的源码细节,帮助你在应用启动、请求处理与关闭各阶段正确管理数据库连接。

DataSource 是什么

按照 官方文档 的定义,与数据库的一切交互都建立在 DataSource 之上:

  • DataSource 持有你的数据库连接配置;
  • 根据所使用的 RDBMS,它负责建立单个初始数据库连接连接池
  • 调用实例的 initialize() 方法完成初始连接/连接池的建立;
  • 调用 destroy() 方法关闭连接(即关闭池中所有连接)。

一般约定是在应用启动(bootstrap)阶段调用 initialize(),在停止使用数据库后调用 destroy()。但实践中,如果你构建的是网站的后台服务且服务器长期运行,通常从不销毁 DataSource——保持连接池常驻是更常见的做法。

这一约定在 DataSource 源码 的类注释中有明确呼应:DataSource 被定义为"to a specific database 的预定义连接配置",一个应用中可以存在多个 DataSource、连接多个数据库。

创建一个新的 DataSource

创建 DataSource 实例的方式是调用 new DataSource(...) 并传入 DataSourceOptions,然后将其赋值给一个全局可用的变量(建议 export,因为在整个应用中都会复用该实例):

import { DataSource } from "typeorm"

const AppDataSource = new DataSource({
    type: "mysql",
    host: "localhost",
    port: 3306,
    username: "test",
    password: "test",
    database: "test",
})

try {
    await AppDataSource.initialize()
    console.log("Data Source has been initialized!")
} catch (error) {
    console.error("Error during Data Source initialization", error)
}

文档明确建议将 AppDataSourceexport 的方式全局暴露,后续所有模块都通过导入它来访问数据库,而不是各处自建连接。

DataSource 接收的参数类型是 DataSourceOptions,它是一个按数据库 type 划分的联合类型——不同的数据库 type 对应不同的可配置选项。从 DriverFactory 可以看出 type 到驱动类的完整映射,当前仓库支持的取值包括:aurora-mysqlaurora-postgresbetter-sqlite3capacitorcockroachdbcordovaexpomariadb(复用 MysqlDriver)、mongodbmssqlmysqlnativescriptoraclepostgresreact-nativesapspannersqljs;传入未识别的 type 会抛出 MissingDriverError

从源码看构造函数做了什么

new DataSource(options) 并不只是保存配置。查看 DataSource 构造函数,它在实例化阶段就完成了一系列装配:

  1. options 保存:原始配置存于 this.options,之后可通过只读属性访问;
  2. 创建 Logger:通过 LoggerFactory 依据 loggerlogging 选项生成日志器;
  3. 创建 Drivernew DriverFactory().create(this) 依据 type 选出具体数据库驱动;
  4. 创建 EntityManagerthis.manager = this.createEntityManager(),即后续执行实体操作的入口;
  5. 设置命名策略:默认使用 DefaultNamingStrategy,可用 namingStrategy 选项覆盖;
  6. 设置元数据表名metadataTableName 默认值为 "typeorm_metadata"
  7. 创建查询结果缓存(可选):若配置了 cache,通过 QueryResultCacheFactory 创建缓存实例;
  8. isInitialized 置为 false,等待 initialize()

可以推断,构造函数保持轻量、不做任何网络 I/O,真正与数据库的交互全部延迟到 initialize()

initialize 与 destroy 的内部流程

initialize() 方法 的执行顺序是:

  1. isInitialized 已为 true,抛出 CannotConnectAlreadyConnectedError(重复初始化防护);
  2. 校验 isolationLevel 是否被驱动支持(validateIsolationLevel);
  3. await this.driver.connect() 建立真实连接/连接池;
  4. 若启用缓存,连接缓存后端;
  5. isInitialized = true,随后调用 buildMetadatas() 构建全部实体元数据(内部经 ConnectionMetadataBuilder 加载 entities / subscribers / migrations,并对元数据做合法性校验);
  6. 若配置了 dropSchema,执行 dropDatabase();若配置了 migrationsRun,按 migrationsTransactionMode 自动运行迁移;若配置了 synchronize,自动同步数据库结构;
  7. 上述构建阶段任何一步失败,都会destroy() 再抛出错误,保证连接不会处于半初始化状态。

与之对称,destroy() 方法 要求连接已建立(否则抛出 CannotExecuteNotConnectedError),随后断开驱动连接、断开缓存连接,并将 isInitialized 重置为 false

功能测试 对这些边界做了验证:连接建立前 dataSource.isInitialized 应为 false,此时调用 destroy()synchronize() 均会以 CannotExecuteNotConnectedError 被拒绝,而 initialize() 应当成功返回。

DataSourceOptions:连接配置详解

DataSourceOptions 是创建 DataSource 时传入的连接配置,不同 RDBMS 有其专属选项。所有类型共享的基础选项定义在 BaseDataSourceOptions 接口中,主要包括:

选项 说明
type 数据库类型,必填,决定使用哪个驱动(取值见上文 DriverFactory 列表)
entities 要加载的实体:实体类、EntitySchema 或支持 glob 的目录路径,如 [Post, Category, "entities/*.js"]
subscribers 要加载的订阅者:类或 glob 目录
migrations 要加载的迁移:类或 glob 目录
migrationsRun 每次应用启动时是否自动执行迁移(生产环境请谨慎,可用 CLI 的 migrations:run 替代)
migrationsTableName 迁移记录表名(默认 migrations
migrationsTransactionMode 迁移执行事务模式:"all" / "none" / "each"
metadataTableName ORM 元数据表名,默认 "typeorm_metadata"
namingStrategy 自定义表/列命名策略
logging / logger 日志开关与日志器(可选 "advanced-console""simple-console""formatted-console""file""debug" 或自定义 Logger 实现)
maxQueryExecutionTime 超过该毫秒数的查询会被日志记录
poolSize 连接池最大连接数
synchronize 启动时自动同步数据库结构,生产环境慎用(可用 CLI schema:sync 替代);对 MongoDB 不建 schema,只创建索引
dropSchema 每次初始化时清空数据库,仅限开发调试
entityPrefix 为该数据源中所有表(集合)添加前缀
entitySkipConstructor 反序列化实体时跳过构造函数(会失去私有属性与默认值的行为保证)
extra 透传给底层驱动(pgmysql2tediousmongodb 等)的原生连接选项,是 TypeORM 未直接建模的驱动级设置的"逃生舱"
cache 查询结果缓存配置("database" / "redis" 等后端,含 durationalwaysEnabled 等)
isolateWhereStatements 自动为每个 where 条件加括号隔离
invalidWhereValuesBehavior find/update 等高层操作中 where 条件遇到 null/undefined 的行为(ignore / sql-null / throw
relationLoadStrategy 关联加载默认策略:"join""query"
isolationLevel 事务默认隔离级别,须为驱动支持的级别

各数据库的专属选项(如 MySQL 的 host / port / database、Postgres 的 ssl、Aurora 的 region / secretArn 等)见 Data Source Options 文档

仓库根目录的 ormconfig.sample.json 是一份可参考的真实配置数组,展示了各驱动典型的必填项,例如:

{
    "type": "mssql",
    "host": "localhost",
    "port": 1433,
    "username": "sa",
    "password": "Admin12345",
    "database": "tempdb",
    "logging": false,
    "extra": {
        "trustServerCertificate": true
    }
}

以及 MySQL:

{
    "type": "mysql",
    "host": "localhost",
    "port": 3306,
    "username": "root",
    "password": "admin",
    "database": "typeorm",
    "logging": false
}

可以看到 typehostportusernamepassworddatabase 是远程数据库的典型必填项,而 better-sqlite3sqljs 这类嵌入式数据库只需 database(文件路径)甚至无需任何连接参数。

使用多个 DataSource

一个应用中可以定义任意多个 DataSource 实例,每个指向不同的数据库。文档给出的双数据源示例:

import { DataSource } from "typeorm"

const MysqlDataSource = new DataSource({
    type: "mysql",
    host: "localhost",
    port: 3306,
    username: "test",
    password: "test",
    database: "test",
    entities: [__dirname + "/entities/**/*{.js,.ts}"],
})

const PostgresDataSource = new DataSource({
    type: "postgres",
    host: "localhost",
    port: 5432,
    username: "test",
    password: "test",
    database: "test",
    entities: [__dirname + "/entities/**/*{.js,.ts}"],
})

两个实例各自独立初始化、独立持有连接池与实体元数据。除多数据源外,TypeORM 还支持在单个数据源内使用多个数据库(仅 MySQL/SQL Server)与多个 schema(PostgreSQL/SQL Server),以及基于 replication 选项的主从读写分离,详见 Multiple Data Sources 文档

如何使用 DataSource

DataSource 初始化完成后,可以在应用任何位置使用它。文档给出的控制器示例:

import { AppDataSource } from "./app-data-source"
import { User } from "../entity/User"

export class UserController {
    @Get("/users")
    getAll() {
        return AppDataSource.manager.find(User)
    }
}

核心是 DataSource 的两个主要访问通道:

  • .managerEntityManager 实例,提供 findsaveremovetransaction 等实体级操作,详见 Entity Manager 文档
  • .getRepository(Entity):返回特定实体的 Repository,将操作进一步收敛到单个实体上,详见 Repository 文档

此外,DataSource 还提供了一整套面向 schema、迁移与原始 SQL 的 API,包括 synchronize()dropDatabase()runMigrations()undoLastMigration()getMetadata()transaction()query()sql(模板字符串 SQL 标签)、createQueryBuilder()createQueryRunner() 等,完整签名与用法见 Data Source API 文档DataSource 源码。例如原始 SQL 查询支持按驱动区分占位符语法:

const rawData = await AppDataSource.query(
    "SELECT * FROM USERS WHERE name = ? and age = ?",  // MySQL 族
    ["John", 24],
)

在需要手动控制单条数据库连接与事务时(如读写分离场景下指定 master/slave),通过 AppDataSource.createQueryRunner(mode) 获取 QueryRunner,用完后务必 release() 归还连接池。

小结与最佳实践

  • 应用启动时 initialize(),长驻服务不必 destroy();退出流程或需要重连时再显式销毁;
  • 重复 initialize() 会抛 CannotConnectAlreadyConnectedError,未连接时执行操作会抛 CannotExecuteNotConnectedError,这两个错误可作为连接状态异常的明确信号;
  • synchronizedropSchema 属于开发期选项,生产环境应使用 CLI 或迁移管理结构变更(migrationsRun 同样建议配合 CI 使用而非常驻开启);
  • AppDataSourceexport 全局暴露,业务代码统一经 .manager / .getRepository() 访问;
  • 驱动级原生选项统一走 extra 透传,共享选项优先使用 BaseDataSourceOptions 中已建模的字段。

相关源码入口:DataSource 实现基础选项定义驱动工厂元数据构建器DataSource 功能测试

登录后查看全文
热门项目推荐
相关项目推荐