TypeORM DataSource 完全指南:创建、初始化与数据库连接的工程实践
在 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)
}
文档明确建议将 AppDataSource 以 export 的方式全局暴露,后续所有模块都通过导入它来访问数据库,而不是各处自建连接。
DataSource 接收的参数类型是 DataSourceOptions,它是一个按数据库 type 划分的联合类型——不同的数据库 type 对应不同的可配置选项。从 DriverFactory 可以看出 type 到驱动类的完整映射,当前仓库支持的取值包括:aurora-mysql、aurora-postgres、better-sqlite3、capacitor、cockroachdb、cordova、expo、mariadb(复用 MysqlDriver)、mongodb、mssql、mysql、nativescript、oracle、postgres、react-native、sap、spanner、sqljs;传入未识别的 type 会抛出 MissingDriverError。
从源码看构造函数做了什么
new DataSource(options) 并不只是保存配置。查看 DataSource 构造函数,它在实例化阶段就完成了一系列装配:
options保存:原始配置存于this.options,之后可通过只读属性访问;- 创建 Logger:通过
LoggerFactory依据logger与logging选项生成日志器; - 创建 Driver:
new DriverFactory().create(this)依据type选出具体数据库驱动; - 创建 EntityManager:
this.manager = this.createEntityManager(),即后续执行实体操作的入口; - 设置命名策略:默认使用
DefaultNamingStrategy,可用namingStrategy选项覆盖; - 设置元数据表名:
metadataTableName默认值为"typeorm_metadata"; - 创建查询结果缓存(可选):若配置了
cache,通过QueryResultCacheFactory创建缓存实例; - 将
isInitialized置为false,等待initialize()。
可以推断,构造函数保持轻量、不做任何网络 I/O,真正与数据库的交互全部延迟到 initialize()。
initialize 与 destroy 的内部流程
initialize() 方法 的执行顺序是:
- 若
isInitialized已为true,抛出CannotConnectAlreadyConnectedError(重复初始化防护); - 校验
isolationLevel是否被驱动支持(validateIsolationLevel); await this.driver.connect()建立真实连接/连接池;- 若启用缓存,连接缓存后端;
- 置
isInitialized = true,随后调用buildMetadatas()构建全部实体元数据(内部经 ConnectionMetadataBuilder 加载 entities / subscribers / migrations,并对元数据做合法性校验); - 若配置了
dropSchema,执行dropDatabase();若配置了migrationsRun,按migrationsTransactionMode自动运行迁移;若配置了synchronize,自动同步数据库结构; - 上述构建阶段任何一步失败,都会先
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 |
透传给底层驱动(pg、mysql2、tedious、mongodb 等)的原生连接选项,是 TypeORM 未直接建模的驱动级设置的"逃生舱" |
cache |
查询结果缓存配置("database" / "redis" 等后端,含 duration、alwaysEnabled 等) |
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
}
可以看到 type、host、port、username、password、database 是远程数据库的典型必填项,而 better-sqlite3、sqljs 这类嵌入式数据库只需 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 的两个主要访问通道:
.manager:EntityManager实例,提供find、save、remove、transaction等实体级操作,详见 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,这两个错误可作为连接状态异常的明确信号; synchronize与dropSchema属于开发期选项,生产环境应使用 CLI 或迁移管理结构变更(migrationsRun同样建议配合 CI 使用而非常驻开启);AppDataSource以export全局暴露,业务代码统一经.manager/.getRepository()访问;- 驱动级原生选项统一走
extra透传,共享选项优先使用 BaseDataSourceOptions 中已建模的字段。
相关源码入口:DataSource 实现、基础选项定义、驱动工厂、元数据构建器、DataSource 功能测试。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00