TypeORM 入门教程
目录
什么是 TypeORM
TypeORM 是一个基于 TypeScript 的 ORM(Object-Relational Mapping,对象关系映射) 框架,它可以帮助你:
- 用 类和装饰器 来定义数据库表结构
- 用 面向对象的方式 操作数据库,而不是写原生 SQL
- 自动处理 数据库表之间的关联关系
- 支持 多种数据库(MySQL、PostgreSQL、SQLite、MongoDB 等)
简单来说,TypeORM 让你可以像操作 JavaScript 对象一样操作数据库。
安装与配置
1. 安装依赖
bash
# npm
npm install typeorm reflect-metadata mysql2
# yarn
yarn add typeorm reflect-metadata mysql2
💡
reflect-metadata是必须的,TypeORM 依赖它实现装饰器功能。
2. 创建数据库连接
在项目入口文件(如 index.ts 或 app.ts)中创建连接:
typescript
import 'reflect-metadata'
import { createConnection } from 'typeorm'
async function main() {
const connection = await createConnection({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: '123456',
database: 'my_database',
entities: [__dirname + '/entity/*.ts'], // 实体文件路径
synchronize: true, // 开发环境自动同步表结构(生产环境禁用!)
logging: true, // 打印 SQL 日志
})
console.log('数据库连接成功!')
}
main().catch(console.error)
3. 配置 ormconfig.json(推荐)
创建项目根目录的 ormconfig.json 文件,方便管理:
json
{
"type": "mysql",
"host": "localhost",
"port": 3306,
"username": "root",
"password": "123456",
"database": "my_database",
"entities": ["src/entity/**/*.ts"],
"synchronize": true,
"logging": true
}
这样创建连接时可以简化:
typescript
import { createConnection } from 'typeorm'
// 自动读取 ormconfig.json 配置
const connection = await createConnection()
核心概念
1. Entity(实体)
实体 = 数据库表,用 TypeScript 类 + 装饰器定义。
2. Repository(仓库)
仓库 = 操作数据库的 API,提供 CRUD 方法。
3. Connection(连接)
连接 = 数据库会话,管理所有数据库操作。
4. Decorator(装饰器)
TypeORM 使用装饰器来定义表结构和关联关系。
实体定义
基础实体
typescript
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'
@Entity('users') // 映射到 users 表
export class User {
@PrimaryGeneratedColumn() // 主键,自增
id: number
@Column() // 普通列
name: string
@Column({ unique: true }) // 唯一约束
email: string
@Column({ nullable: true }) // 允许为空
age: number
@Column({ default: 'active' }) // 默认值
status: string
@Column({
type: 'timestamp',
default: () => 'CURRENT_TIMESTAMP', // 默认当前时间
})
createdAt: Date
}
常用列类型
typescript
@Column({ type: 'varchar', length: 100 }) // 字符串,最大100
@Column({ type: 'text' }) // 长文本
@Column({ type: 'int' }) // 整数
@Column({ type: 'decimal', precision: 10, scale: 2 }) // 精确数字
@Column({ type: 'boolean' }) // 布尔
@Column({ type: 'json' }) // JSON 对象
CRUD 操作
获取 Repository
typescript
import { getRepository } from 'typeorm'
import { User } from './entity/User'
const userRepository = getRepository(User)
创建(Create)
typescript
// 方式 1:直接创建
const user = new User()
user.name = '张三'
user.email = 'zhangsan@example.com'
await userRepository.save(user)
// 方式 2:使用 create() 方法
const user = userRepository.create({
name: '李四',
email: 'lisi@example.com',
})
await userRepository.save(user)
// 批量创建
const users = userRepository.create([
{ name: '王五', email: 'wangwu@example.com' },
{ name: '赵六', email: 'zhaoliu@example.com' },
])
await userRepository.save(users)
读取(Read)
typescript
// 根据 ID 查找
const user = await userRepository.findOne(1)
// 查找多个
const users = await userRepository.find()
// 条件查询
const users = await userRepository.find({
where: { status: 'active' },
order: { id: 'DESC' }, // 降序
take: 10, // 限制返回 10 条
})
// 查找或创建(如果不存在则创建)
const user = await userRepository.findOneOrCreate({
where: { email: 'test@example.com' },
defaults: { name: '新用户' },
})
// 统计数量
const count = await userRepository.count()
更新(Update)
typescript
// 根据 ID 更新
await userRepository.update(1, { name: '新名字' })
// 批量更新
await userRepository.update(
{ status: 'inactive' },
{ status: 'deleted' }
)
// 先查找再更新
const user = await userRepository.findOne(1)
user.name = '更新后的名字'
await userRepository.save(user) // save 会自动识别是新增还是更新
删除(Delete)
typescript
// 根据 ID 删除
await userRepository.delete(1)
// 根据条件删除
await userRepository.delete({ status: 'deleted' })
// 先查找再删除
const user = await userRepository.findOne(1)
await userRepository.remove(user)
关联关系
TypeORM 支持三种关联关系:
| 关系类型 | SQL 术语 | 说明 |
|---|---|---|
| OneToOne | 1:1 | 一对一 |
| OneToMany | 1:N | 一对多 |
| ManyToOne | N:1 | 多对一 |
| ManyToMany | N:N | 多对多 |
一对一(OneToOne)
typescript
import { Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm'
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number
@Column()
name: string
@OneToOne(() => UserProfile, profile => profile.user)
@JoinColumn() // 创建外键列
profile: UserProfile
}
@Entity()
export class UserProfile {
@PrimaryGeneratedColumn()
id: number
@Column()
bio: string
@OneToOne(() => User, user => user.profile)
user: User
}
一对多(OneToMany)/ 多对一(ManyToOne)
typescript
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number
@OneToMany(() => Photo, photo => photo.user)
photos: Photo[]
}
@Entity()
export class Photo {
@PrimaryGeneratedColumn()
id: number
@Column()
url: string
@ManyToOne(() => User, user => user.photos)
user: User
}
查询关联数据
typescript
// 使用 relations 选项
const user = await userRepository.findOne(1, {
relations: ['photos'], // 加载关联的 photos
})
console.log(user.photos) // [Photo, Photo, ...]
查询构建器
TypeORM 提供 QueryBuilder 用于构建复杂查询:
typescript
import { getRepository } from 'typeorm'
// 简单查询
const users = await getRepository(User)
.createQueryBuilder('user')
.where('user.name = :name', { name: '张三' })
.getMany()
// 联表查询
const photos = await getRepository(Photo)
.createQueryBuilder('photo')
.leftJoinAndSelect('photo.user', 'user') // 左连接
.where('user.name = :name', { name: '张三' })
.getMany()
// 分页查询
const users = await getRepository(User)
.createQueryBuilder('user')
.skip(0) // 跳过前 10 条
.take(10) // 每页 10 条
.orderBy('user.id', 'DESC')
.getMany()
// 聚合查询
const result = await getRepository(User)
.createQueryBuilder('user')
.select('COUNT(user.id)', 'count')
.where('user.status = :status', { status: 'active' })
.getRawOne() // 获取原始结果
数据库迁移
1. 创建迁移文件
bash
npx typeorm migration:create src/migration/CreateUserTable
2. 编写迁移代码
typescript
import { MigrationInterface, QueryRunner, Table } from 'typeorm'
export class CreateUserTable1234567890 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'users',
columns: [
{
name: 'id',
type: 'int',
isPrimary: true,
isGenerated: true,
generationStrategy: 'increment',
},
{
name: 'name',
type: 'varchar',
length: '100',
isNullable: false,
},
{
name: 'email',
type: 'varchar',
length: '100',
isUnique: true,
},
{
name: 'created_at',
type: 'timestamp',
default: 'now()',
},
],
}),
true
)
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('users')
}
}
3. 运行迁移
bash
# 执行所有待执行的迁移
npx typeorm migration:run
# 回滚最近一次迁移
npx typeorm migration:revert
最佳实践
1. 环境配置
typescript
// 开发环境:synchronize: true(自动同步表结构)
// 生产环境:synchronize: false,使用 migration 管理表结构
2. 使用 Repository 模式
typescript
// ✅ 推荐:使用 Repository
const user = await userRepository.findOne(1)
// ❌ 避免:直接使用 QueryRunner
const user = await connection.query('SELECT * FROM users WHERE id = 1')
3. 处理关联关系
typescript
// 避免 N+1 查询问题,使用 addSelectAndMap 或 QueryBuilder
const users = await getRepository(User)
.createQueryBuilder('user')
.leftJoinAndSelect('user.photos', 'photo')
.getMany()
4. 错误处理
typescript
import { QueryFailedError } from 'typeorm'
try {
await userRepository.save(user)
} catch (error) {
if (error instanceof QueryFailedError) {
// 处理数据库错误(如唯一约束冲突)
console.error('数据库错误:', error.message)
}
throw error
}
5. 事务处理
typescript
import { getManager } from 'typeorm'
await getManager().transaction(async transactionManager => {
// 在事务中执行多个操作
await transactionManager.save(user)
await transactionManager.save(order)
// 任意一个操作失败,整个事务会回滚
})
6. 使用 DTO 和 Validation
typescript
import { IsString, IsEmail, MinLength } from 'class-validator'
export class CreateUserDto {
@IsString()
@MinLength(2)
name: string
@IsEmail()
email: string
}
常见问题
Q: synchronize: true 在生产环境有什么风险?
A: 它会自动修改数据库结构,可能导致数据丢失。生产环境应该使用 migration 管理表结构。
Q: 如何处理软删除?
A: 使用 @DeleteDateColumn() 装饰器:
typescript
@Column({ name: 'deleted_at', nullable: true, select: false })
deletedAt: Date
// 查询时自动过滤已删除的数据
const users = await userRepository.find({ withDeleted: false })
Q: 如何优化性能?
A:
- 只查询需要的字段(
select选项) - 使用
eager: false(默认),按需加载关联数据 - 合理使用索引
- 避免 N+1 查询问题
总结
TypeORM 通过 装饰器 + 面向对象 的方式,让数据库操作变得简单直观:
| 功能 | 方法 |
|---|---|
| 定义表结构 | @Entity + @Column |
| 主键 | @PrimaryGeneratedColumn |
| CRUD | repository.find/save/update/delete |
| 关联关系 | @OneToOne/OneToMany/ManyToOne/ManyToMany |
| 复杂查询 | QueryBuilder |
| 表结构迁移 | migration:create + migration:run |
掌握这些核心概念,你就可以开始用 TypeORM 开发了!🚀
📅 创建时间:2026-08-13