在TypeScript驱动的Node.js后端项目中,数据库操作的选择一直是开发者关注的焦点,要么直接编写原生SQL语句保证灵活性,要么使用ORM框架提升开发效率。TypeORM作为专门为TypeScript设计的ORM框架,很好地平衡了这两者的需求,既支持原生SQL的执行,也提供了类型友好的查询方式。

TypeORM的基础配置与实体定义
使用TypeORM前需要先完成基础配置,同时定义好对应数据库表的实体类,这是框架运作的基础。以下是一个简单的MySQL数据库连接配置示例:
import { createConnection } from 'typeorm';
// 建立数据库连接配置
createConnection({
type: 'mysql',
host: '127.0.0.1',
port: 3306,
username: 'root',
password: '123456',
database: 'test_db',
entities: [__dirname + '/entity/*.js'],
synchronize: true, // 开发环境可开启自动同步表结构,生产环境建议关闭
logging: false,
}).then(() => {
console.log('数据库连接成功');
}).catch((err) => {
console.error('数据库连接失败', err);
});实体类的定义需要和数据库表结构对应,同时利用TypeScript的类型标注明确字段类型,以下是一个用户表的实体定义示例:
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn } from 'typeorm';
@Entity('user') // 对应数据库中的user表
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({ length: 50 })
username: string;
@Column()
age: number;
@CreateDateColumn()
create_time: Date;
}TypeORM中执行原生SQL语句
当需要进行复杂查询或者优化查询性能时,直接使用原生SQL是更高效的选择,TypeORM提供了多种方式执行原生SQL语句。
使用query方法执行普通SQL
通过query方法可以直接执行任意SQL语句,适合简单的查询和更新操作:
import { getManager } from 'typeorm';
// 查询年龄大于18的用户
const users = await getManager().query('SELECT * FROM user WHERE age > 18');
console.log(users);
// 更新用户信息
await getManager().query('UPDATE user SET age = ? WHERE id = ?', [25, 1]);使用参数化查询避免SQL注入
直接拼接SQL字符串存在SQL注入风险,TypeORM支持参数化查询,将参数和SQL语句分离:
// 参数化查询示例,用?作为占位符
const userId = 1;
const user = await getManager().query('SELECT * FROM user WHERE id = ?', [userId]);TypeORM的查询构建器使用
除了原生SQL,TypeORM还提供了查询构建器,基于TypeScript类型生成SQL语句,同时保留SQL的可读性,适合大部分常规查询场景。
基础查询示例
查询构建器的语法和SQL结构类似,同时支持TypeScript的类型提示:
import { getRepository } from 'typeorm';
import { User } from './entity/User';
// 查询所有年龄大于20的用户,按创建时间倒序排列
const userList = await getRepository(User)
.createQueryBuilder('user')
.where('user.age > :age', { age: 20 })
.orderBy('user.create_time', 'DESC')
.getMany();
console.log(userList);关联查询示例
当需要进行多表关联查询时,查询构建器也能很好地支持,以下是一个用户和订单的关联查询示例,假设订单实体Order和User存在多对一关系:
import { Order } from './entity/Order';
// 查询用户及其所有订单
const result = await getRepository(User)
.createQueryBuilder('user')
.leftJoinAndSelect('user.orders', 'order') // 左连接订单表
.where('user.id = :id', { id: 1 })
.getOne();
console.log(result);原生SQL与查询构建器的选择建议
在实际开发中,可以根据场景灵活选择两种查询方式,以下是两者的对比参考:
| 对比维度 | 原生SQL | 查询构建器 |
|---|---|---|
| 灵活性 | 高,支持所有SQL语法 | 中,仅支持框架封装的语法 |
| 类型安全 | 低,无TypeScript类型提示 | 高,有完整的类型校验 |
| 开发效率 | 低,需要手动编写完整SQL | 高,语法简洁且有提示 |
| 适用场景 | 复杂查询、性能优化、数据库特有语法 | 常规CRUD、简单关联查询 |
事务处理中的SQL使用
在需要保证数据一致性的场景中,事务是必不可少的,TypeORM支持在事务中混合使用原生SQL和查询构建器:
import { getConnection } from 'typeorm';
await getConnection().transaction(async (transactionalEntityManager) => {
// 使用查询构建器插入用户
const user = new User();
user.username = 'test_user';
user.age = 22;
await transactionalEntityManager.save(user);
// 使用原生SQL更新其他相关数据
await transactionalEntityManager.query('UPDATE user_count SET count = count + 1 WHERE type = 1');
});通过以上的介绍可以看出,TypeORM并没有限制开发者使用原生SQL的能力,而是在TypeScript的类型体系下,为SQL的使用提供了更友好的封装。开发者可以根据实际需求,在原生SQL的灵活性和查询构建器的开发效率之间自由切换,既不会丢失SQL的控制权,也能享受到TypeScript带来的类型安全保障。
TypeORMTypeScriptSQL数据库开发ORM修改时间:2026-05-27 23:33:28