1. 什么是 ORM
ORM(Object Relational Mapping)
中文:
对象关系映射
它是一种将关系型数据库 与面向对象编程语言进行映射的技术。
简单来说:
操作数据库
=
操作对象
而不是直接编写 SQL。
传统方式
SQL:
SELECT * FROM users WHERE id = 1;
Node.js:
const result = await connection.query(
'SELECT * FROM users WHERE id = 1'
);
ORM方式
const user = await userRepository.findOne({
where: {
id: 1
}
});
开发者操作的是对象。
ORM 自动生成 SQL。
2. ORM 的核心思想
ORM 本质上是一层映射关系。
数据库与对象的映射
| 数据库 | ORM |
|---|---|
| Database | 数据库 |
| Table | 类(Class) |
| Row | 对象(Object) |
| Column | 属性(Property) |
| Primary Key | 主键字段 |
| Foreign Key | 对象关联 |
例如:
数据库表:
users
| id | name | age |
|---|---|---|
| 1 | Tom | 20 |
对应:
class User {
id: number;
name: string;
age: number;
}
数据库记录:
1 Tom 20
映射为:
{
id:1,
name:'Tom',
age:20
}
3. ORM 的工作原理
以查询用户为例:
const user = await userRepository.findOne({
where: { id: 1 }
});
执行流程:
代码
↓
ORM
↓
生成SQL
↓
数据库执行
↓
返回结果
↓
转换对象
↓
返回程序
生成的 SQL:
SELECT *
FROM users
WHERE id = 1;
4. ORM 解决了什么问题
问题1:SQL编写繁琐
传统:
const sql =
`
SELECT *
FROM users
WHERE age > 18
`;
大量业务代码中:
SQL
SQL
SQL
SQL
SQL
难维护。
问题2:数据库切换困难
假设:
MySQL
↓
PostgreSQL
SQL语法可能不同。
ORM封装后:
userRepository.find()
代码几乎不用改。
问题3:对象与数据转换
传统:
const result = await query(...)
const user = {
id: result[0].id,
name: result[0].name
}
ORM自动完成转换。
5. ORM 常见操作
查询
await userRepository.find()
SQL:
SELECT * FROM users;
条件查询
await userRepository.find({
where:{
age:18
}
})
SQL:
SELECT *
FROM users
WHERE age = 18;
插入
await userRepository.save({
name:'Tom',
age:20
})
SQL:
INSERT INTO users(name,age)
VALUES('Tom',20);
更新
await userRepository.update(
1,
{
age:30
}
)
SQL:
UPDATE users
SET age = 30
WHERE id = 1;
删除
await userRepository.delete(1)
SQL:
DELETE FROM users
WHERE id = 1;
6. ORM 的核心组成
Entity(实体)
实体对应数据库表。
TypeORM:
@Entity()
export class User {
@PrimaryGeneratedColumn()
id:number;
@Column()
name:string;
}
对应:
CREATE TABLE users(
id INT,
name VARCHAR(255)
)
Repository(仓库)
负责增删改查。
@InjectRepository(User)
private userRepository: Repository<User>;
使用:
this.userRepository.find()
Migration(迁移)
用于管理数据库结构变化。
例如:
新增字段
修改字段
删除字段
通过迁移同步数据库。
Relationship(关系映射)
管理表之间关系。
例如:
用户
↓
订单
7. ORM中的关系映射
一对一(One To One)
例如:
用户
↔
身份证
@OneToOne()
一对多(One To Many)
例如:
用户
↓
订单
一个用户多个订单。
@OneToMany()
多对一(Many To One)
订单
↓
用户
多个订单属于一个用户。
@ManyToOne()
多对多(Many To Many)
例如:
学生
↔
课程
一个学生多门课。
一门课多个学生。
@ManyToMany()
8. ORM 常见框架
Node.js
TypeORM
特点:
NestJS官方推荐
装饰器丰富
学习简单
示例:
await repository.find()
Prisma
目前最火。
特点:
类型安全
自动生成TS类型
性能较好
示例:
await prisma.user.findMany()
Sequelize
老牌ORM。
User.findAll()
9. TypeORM 与 Prisma 对比
| 对比项 | TypeORM | Prisma |
|---|---|---|
| 学习成本 | 低 | 低 |
| 类型安全 | 一般 | 强 |
| NestJS支持 | 官方示例多 | 很好 |
| 社区成熟度 | 高 | 高 |
| 自动生成类型 | 否 | 是 |
| 性能 | 一般 | 较好 |
| 推荐程度 | ★★★★ | ★★★★★ |
10. ORM 的优点
提高开发效率
不用频繁写 SQL。
userRepository.save(user)
即可完成保存。
面向对象
符合开发习惯。
user.name = 'Tom'
而不是:
UPDATE ...
减少重复代码
CRUD操作统一。
降低 SQL 注入风险
ORM自动处理参数。
例如:
find({
where:{
name:input
}
})
自动参数化。
提高代码可维护性
数据库逻辑集中管理。
11. ORM 的缺点
性能损耗
ORM:
user.posts.comments.author
可能生成大量 SQL。
学习成本
需要学习:
实体
关系映射
Repository
QueryBuilder
Migration
复杂查询不方便
例如:
GROUP BY
UNION
窗口函数
复杂JOIN
ORM写法反而更复杂。
N+1 问题
例如:
查询100个用户
↓
查询100次订单
最终:
1 + 100
=
101次SQL
性能极差。
12. ORM 与 SQL 的关系
很多新人误解:
学ORM
=
不用学SQL
这是错误的。
正确理解:
SQL
↓
基础
↓
ORM
↓
高级封装
真正的后端开发:
70%
ORM
20%
Query Builder
10%
原生SQL
复杂统计分析依然离不开 SQL。
13. NestJS 中的 ORM
最常见架构:
Controller
↓
Service
↓
Repository(TypeORM)
↓
MySQL
示意图:
HTTP请求
↓
Controller
↓
Service
↓
TypeORM
↓
MySQL
14. 面试必背总结
什么是 ORM?
ORM(Object Relational Mapping)是一种对象关系映射技术,它建立了程序对象与数据库表之间的映射关系,使开发者能够通过操作对象完成数据库操作,而无需直接编写大量 SQL。
ORM 的核心映射关系?
Table ↔ Class
Row ↔ Object
Column ↔ Property
ORM 的优点?
提高开发效率
减少SQL编写
面向对象开发
降低SQL注入风险
提高可维护性
ORM 的缺点?
性能开销
复杂查询困难
存在N+1问题
需要理解底层SQL
NestJS 常用 ORM?
TypeORM
Prisma
其中:
TypeORM = 官方教程常用
Prisma = 当前企业新项目趋势
一句话记忆:
ORM 就是数据库和程序对象之间的翻译官,让开发者用操作对象的方式完成数据库操作。