NestJS与MySQL整合开发实战指南
2026/7/22 9:11:14 网站建设 项目流程

1. Nest框架与MySQL数据库入门指南

作为现代Node.js后端开发的主流框架,NestJS凭借其模块化设计和TypeScript支持,已成为企业级应用开发的热门选择。而MySQL作为最流行的关系型数据库之一,与Nest的整合是每个全栈开发者必须掌握的技能。本文将带你从零开始搭建Nest项目,并实现完整的MySQL数据库操作流程。

提示:本文基于Nest 9.x和MySQL 8.0环境,所有代码示例均通过TypeScript 4.7验证

1.1 环境准备与项目初始化

首先确保你的开发环境已安装:

  • Node.js 16+(推荐18.x LTS版本)
  • MySQL 8.0+(社区版即可)
  • 任意代码编辑器(VS Code为首选)

通过以下命令创建新项目:

npm i -g @nestjs/cli nest new nest-mysql-demo cd nest-mysql-demo

安装MySQL驱动和TypeORM(Nest官方推荐的ORM):

npm install @nestjs/typeorm typeorm mysql2

1.2 数据库连接配置

app.module.ts中配置TypeORM连接:

import { TypeOrmModule } from '@nestjs/typeorm'; @Module({ imports: [ TypeOrmModule.forRoot({ type: 'mysql', host: 'localhost', port: 3306, username: 'root', password: 'your_password', database: 'nest_demo', entities: [__dirname + '/**/*.entity{.ts,.js}'], synchronize: true, // 开发环境可用,生产环境必须关闭 }), ], }) export class AppModule {}

警告:synchronize: true会基于实体类自动同步数据库结构,方便开发但可能造成生产环境数据丢失,务必在正式部署时设为false

2. 实体定义与CRUD实现

2.1 创建第一个实体

假设我们要开发用户管理系统,先创建用户实体:

// src/users/user.entity.ts import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'; @Entity() export class User { @PrimaryGeneratedColumn() id: number; @Column({ length: 50 }) username: string; @Column({ select: false }) // 查询时默认不返回密码 password: string; @Column({ default: true }) isActive: boolean; @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) createdAt: Date; }

2.2 实现服务层和数据访问

创建用户模块和服务:

nest generate module users nest generate service users

完善服务逻辑:

// src/users/users.service.ts import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { User } from './user.entity'; @Injectable() export class UsersService { constructor( @InjectRepository(User) private usersRepository: Repository<User>, ) {} async create(user: Partial<User>): Promise<User> { return this.usersRepository.save(user); } async findAll(): Promise<User[]> { return this.usersRepository.find(); } async findOne(id: number): Promise<User> { return this.usersRepository.findOne({ where: { id } }); } async update(id: number, updateData: Partial<User>): Promise<void> { await this.usersRepository.update(id, updateData); } async remove(id: number): Promise<void> { await this.usersRepository.delete(id); } }

2.3 控制器层实现

生成控制器并实现RESTful接口:

nest generate controller users
// src/users/users.controller.ts import { Controller, Get, Post, Body, Param, Put, Delete } from '@nestjs/common'; import { UsersService } from './users.service'; import { User } from './user.entity'; @Controller('users') export class UsersController { constructor(private readonly usersService: UsersService) {} @Post() create(@Body() user: User) { return this.usersService.create(user); } @Get() findAll() { return this.usersService.findAll(); } @Get(':id') findOne(@Param('id') id: string) { return this.usersService.findOne(+id); } @Put(':id') update(@Param('id') id: string, @Body() updateData: Partial<User>) { return this.usersService.update(+id, updateData); } @Delete(':id') remove(@Param('id') id: string) { return this.usersService.remove(+id); } }

3. 高级查询与事务处理

3.1 复杂查询构建

TypeORM提供了强大的查询构建器,以下是几个实用示例:

// 在UsersService中添加方法 async findActiveUsers(): Promise<User[]> { return this.usersRepository .createQueryBuilder('user') .where('user.isActive = :isActive', { isActive: true }) .orderBy('user.createdAt', 'DESC') .getMany(); } async searchUsers(keyword: string): Promise<User[]> { return this.usersRepository .createQueryBuilder() .where('username LIKE :keyword', { keyword: `%${keyword}%` }) .orWhere('email LIKE :keyword', { keyword: `%${keyword}%` }) .getMany(); }

3.2 事务处理实战

对于需要原子性操作的多表写入,必须使用事务:

async transferCredits( fromId: number, toId: number, amount: number, ): Promise<void> { await this.usersRepository.manager.transaction(async (manager) => { const fromUser = await manager.findOne(User, { where: { id: fromId } }); const toUser = await manager.findOne(User, { where: { id: toId } }); if (!fromUser || !toUser) { throw new Error('用户不存在'); } if (fromUser.credits < amount) { throw new Error('余额不足'); } fromUser.credits -= amount; toUser.credits += amount; await manager.save(User, fromUser); await manager.save(User, toUser); }); }

4. 性能优化与生产环境实践

4.1 连接池配置优化

在高并发场景下,合理的连接池配置至关重要:

TypeOrmModule.forRoot({ // ...其他配置 extra: { connectionLimit: 10, // 连接池大小 waitForConnections: true, queueLimit: 0, }, }),

推荐配置规则:

  • 开发环境:5-10个连接
  • 生产环境:按 (核心数 * 2) + 有效磁盘数 计算

4.2 索引与查询优化

为常用查询字段添加索引:

@Entity() export class User { // ... @Column({ length: 50 }) @Index('IDX_USERNAME', { unique: true }) username: string; @Column() @Index('IDX_EMAIL', { unique: true }) email: string; }

查询优化技巧:

  1. 避免SELECT *,只查询必要字段
  2. 对分页查询使用skip()take()替代limitoffset
  3. 复杂查询考虑使用原生SQL

4.3 生产环境部署要点

  1. 必须关闭synchronize,使用迁移管理数据库变更
  2. 启用SSL连接(云数据库必备)
  3. 配置适当的连接超时时间
  4. 实现健康检查端点监控数据库连接状态
// 健康检查示例 @Get('health') async healthCheck() { try { await this.usersRepository.query('SELECT 1'); return { status: 'ok' }; } catch (error) { throw new HttpException( { status: 'down', error: error.message }, HttpStatus.SERVICE_UNAVAILABLE, ); } }

5. 常见问题排查

5.1 连接问题速查表

错误现象可能原因解决方案
ECONNREFUSED数据库服务未启动检查MySQL服务状态
ER_ACCESS_DENIED_ERROR认证失败验证用户名/密码
ER_BAD_DB_ERROR数据库不存在创建指定数据库
ETIMEDOUT网络问题检查防火墙/安全组规则

5.2 性能问题诊断

  1. 慢查询日志分析:
-- 在MySQL中启用慢查询日志 SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1;
  1. 使用EXPLAIN分析查询计划:
const query = this.usersRepository .createQueryBuilder('user') .where('user.isActive = :isActive', { isActive: true }) .getSql(); const explainResult = await this.usersRepository.query( `EXPLAIN ${query}`, );

5.3 事务隔离级别问题

MySQL默认使用REPEATABLE READ隔离级别,可能导致幻读。对于需要更高隔离级别的操作:

async sensitiveOperation() { await this.usersRepository.manager.transaction( 'SERIALIZABLE', async (manager) => { // 事务操作 }, ); }

6. 扩展实践与进阶技巧

6.1 多数据库连接配置

对于需要连接多个MySQL实例的场景:

@Module({ imports: [ TypeOrmModule.forRoot({ name: 'primary', type: 'mysql', // 主数据库配置 }), TypeOrmModule.forRoot({ name: 'secondary', type: 'mysql', // 从数据库配置 }), ], }) export class AppModule {} // 使用时指定连接 @InjectRepository(User, 'secondary') private secondaryUserRepository: Repository<User>

6.2 数据迁移管理

使用TypeORM迁移工具管理数据库变更:

  1. 安装typeorm扩展:
npm install ts-node typeorm -D
  1. 创建迁移:
npx typeorm migration:create src/migrations/InitSchema
  1. 编写迁移文件:
import { MigrationInterface, QueryRunner } from 'typeorm'; export class InitSchema implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise<void> { await queryRunner.query(` CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL, password VARCHAR(100) NOT NULL, isActive BOOLEAN DEFAULT TRUE, createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) `); } public async down(queryRunner: QueryRunner): Promise<void> { await queryRunner.query(`DROP TABLE users`); } }
  1. 运行迁移:
npx typeorm migration:run

6.3 软删除实现

通过装饰器轻松实现软删除:

import { DeleteDateColumn } from 'typeorm'; @Entity() export class User { // ... @DeleteDateColumn() deletedAt?: Date; } // 查询时自动过滤已删除记录 this.usersRepository.find(); // 需要查询已删除记录时 this.usersRepository.find({ withDeleted: true });

7. 安全最佳实践

7.1 敏感数据保护

  1. 密码存储必须加密:
import * as bcrypt from 'bcrypt'; async create(user: Partial<User>): Promise<User> { const salt = await bcrypt.genSalt(); user.password = await bcrypt.hash(user.password, salt); return this.usersRepository.save(user); }
  1. 使用select: false隐藏敏感字段
  2. 实现DTO层过滤返回数据

7.2 SQL注入防护

TypeORM已内置防护措施,但需注意:

  • 始终使用参数化查询
  • 避免直接拼接SQL
  • 对用户输入进行严格验证
// 安全做法 this.usersRepository .createQueryBuilder() .where('username = :username', { username: userInput }); // 危险做法(绝对避免) this.usersRepository.query( `SELECT * FROM users WHERE username = '${userInput}'`, );

7.3 连接安全配置

生产环境必须启用SSL:

TypeOrmModule.forRoot({ ssl: { rejectUnauthorized: true, ca: fs.readFileSync('/path/to/server-ca.pem').toString(), cert: fs.readFileSync('/path/to/client-cert.pem').toString(), key: fs.readFileSync('/path/to/client-key.pem').toString(), }, }),

8. 测试策略

8.1 单元测试示例

使用Jest测试服务层:

describe('UsersService', () => { let service: UsersService; let repository: Repository<User>; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [ UsersService, { provide: getRepositoryToken(User), useClass: Repository, }, ], }).compile(); service = module.get<UsersService>(UsersService); repository = module.get<Repository<User>>(getRepositoryToken(User)); }); it('should create a user', async () => { const userData = { username: 'test', password: '123456' }; jest.spyOn(repository, 'save').mockResolvedValueOnce({ id: 1, ...userData }); const result = await service.create(userData); expect(result).toHaveProperty('id'); expect(repository.save).toHaveBeenCalled(); }); });

8.2 E2E测试配置

测试模块配置使用测试数据库:

@Module({ imports: [ TypeOrmModule.forRoot({ type: 'mysql', host: 'localhost', port: 3307, // 测试数据库端口 username: 'test', password: 'test', database: 'test_db', entities: [__dirname + '/**/*.entity{.ts,.js}'], synchronize: true, // 测试环境可以开启 }), UsersModule, ], }) export class TestModule {}

9. 性能监控与日志

9.1 慢查询监控

集成TypeORM日志记录慢查询:

TypeOrmModule.forRoot({ logging: ['query'], maxQueryExecutionTime: 1000, // 超过1秒的查询记录为慢查询 }),

9.2 自定义查询日志

通过订阅TypeORM事件实现高级日志:

import { Connection, QueryRunner } from 'typeorm'; @Injectable() export class DatabaseLogger implements Logger { constructor(private connection: Connection) { this.connection.subscribe((event) => { if (event.queryRunner?.data?.queryDuration > 500) { console.warn(`Slow query detected: ${event.queryRunner.query}`); } }); } }

10. 项目结构优化建议

10.1 模块化组织

推荐的项目结构:

src/ ├── modules/ │ ├── users/ │ │ ├── user.entity.ts │ │ ├── users.service.ts │ │ ├── users.controller.ts │ │ ├── users.module.ts │ │ └── dto/ │ │ ├── create-user.dto.ts │ │ └── update-user.dto.ts ├── shared/ │ ├── database/ │ │ └── database.module.ts │ └── utils/ └── app.module.ts

10.2 数据库连接集中管理

创建共享的数据库模块:

// src/shared/database/database.module.ts @Module({ imports: [ TypeOrmModule.forRootAsync({ useFactory: () => ({ type: 'mysql', host: process.env.DB_HOST, // ...其他配置 }), }), ], exports: [TypeOrmModule], }) export class DatabaseModule {}

11. 实际项目经验分享

在大型项目中处理千万级用户表时,我们发现几个关键点:

  1. 分库分表策略:当单表超过500万行时,考虑按用户ID哈希分片
  2. 读写分离:配置多个从库分担读压力
  3. 缓存层:对热点数据使用Redis缓存
  4. 连接管理:使用连接中间件如ProxySQL管理连接池

一个实用的连接池监控代码片段:

setInterval(async () => { const pool = this.connection.driver.pool; console.log({ total: pool.totalCount, idle: pool.idleCount, waiting: pool.waitingCount, }); }, 5000);

12. 调试技巧

12.1 查询日志输出

临时开启完整SQL日志:

TypeOrmModule.forRoot({ logger: 'advanced-console', logging: ['query', 'error'], }),

12.2 事务调试

在事务中插入调试点:

await this.usersRepository.manager.transaction(async (manager) => { console.time('transaction'); // 业务代码 console.timeEnd('transaction'); });

13. 版本兼容性说明

不同版本组合的注意事项:

NestJSTypeORMMySQL驱动注意事项
9.x0.3.xmysql2 2.3+推荐组合
8.x0.2.xmysql2 2.2+需要手动安装@nestjs/typeorm
7.x0.2.xmysql 2.18+不支持async/await语法

14. 替代方案比较

14.1 Sequelize vs TypeORM

特性TypeORMSequelize
语法风格装饰器+ActiveRecord传统ORM接口
TypeScript支持原生优秀需要额外类型包
关联查询更直观稍显复杂
社区活跃度极高
迁移工具内置需要单独安装

14.2 原生MySQL驱动

对于简单场景,可以直接使用mysql2包:

import { createPool } from 'mysql2/promise'; const pool = createPool({ host: 'localhost', user: 'root', database: 'test', waitForConnections: true, connectionLimit: 10, }); async function queryUsers() { const [rows] = await pool.query('SELECT * FROM users LIMIT 10'); return rows; }

15. 资源推荐

  1. 官方文档

    • NestJS TypeORM集成
    • TypeORM MySQL配置
  2. 性能优化指南

    • MySQL官方优化白皮书
    • 《高性能MySQL》第3版
  3. 监控工具

    • Percona Monitoring and Management
    • Prometheus + Grafana MySQL仪表板
  4. 安全审计工具

    • sqlmap(用于检测注入漏洞)
    • MySQL Enterprise Audit

16. 升级与迁移策略

从旧版本升级时的注意事项:

  1. 备份优先:执行任何升级前完整备份数据库
  2. 逐步升级:先升级开发环境,验证后再升级生产
  3. 变更日志:仔细阅读TypeORM和Nest的CHANGELOG
  4. 测试覆盖:确保有足够的测试用例验证关键功能

典型升级步骤:

# 1. 备份package.json # 2. 更新依赖 npm install @nestjs/typeorm@latest typeorm@latest mysql2@latest # 3. 运行测试 npm test # 4. 检查弃用警告

17. 云数据库实践

连接云数据库(如AWS RDS)的特殊配置:

TypeOrmModule.forRoot({ type: 'mysql', host: process.env.RDS_HOSTNAME, port: parseInt(process.env.RDS_PORT), username: process.env.RDS_USERNAME, password: process.env.RDS_PASSWORD, database: process.env.RDS_DB_NAME, ssl: { rejectUnauthorized: true, ca: fs.readFileSync('/path/to/rds-combined-ca-bundle.pem').toString(), }, }),

云环境最佳实践:

  1. 使用IAM数据库认证替代密码
  2. 配置自动扩展的连接池
  3. 启用数据库代理减少连接开销
  4. 设置适当的自动备份策略

18. 连接问题深度排查

当遇到间歇性连接断开时,可按以下步骤排查:

  1. 检查MySQL服务器端的wait_timeout设置
  2. 验证TCP keepalive配置
  3. 检查网络设备(负载均衡器、防火墙)的超时设置
  4. 在TypeORM中配置连接验证:
TypeOrmModule.forRoot({ // ... extra: { connectionTimeout: 30000, idleTimeout: 10000, keepAliveInitialDelay: 10000, }, }),

19. 批量操作优化

处理大量数据时的性能技巧:

  1. 使用批量插入代替循环插入:
async bulkCreate(users: User[]) { await this.usersRepository .createQueryBuilder() .insert() .into(User) .values(users) .execute(); }
  1. 分批次处理大数据集:
const batchSize = 1000; for (let i = 0; i < total; i += batchSize) { const batch = data.slice(i, i + batchSize); await this.bulkCreate(batch); }
  1. 禁用日志提升批量操作性能:
await this.usersRepository.manager.transaction(async (manager) => { await manager.query('SET FOREIGN_KEY_CHECKS = 0'); await manager.query('SET UNIQUE_CHECKS = 0'); await manager.query('SET AUTOCOMMIT = 0'); // 批量操作 await manager.query('SET FOREIGN_KEY_CHECKS = 1'); await manager.query('SET UNIQUE_CHECKS = 1'); await manager.query('SET AUTOCOMMIT = 1'); });

20. 数据类型最佳实践

MySQL与TypeScript类型映射建议:

MySQL类型TypeORM装饰器TypeScript类型注意事项
INT@Column('int')number主键推荐使用@PrimaryGeneratedColumn()
VARCHAR@Column('varchar', { length: 255 })string根据实际需求设置长度
TEXT@Column('text')string大文本内容使用
BOOLEAN@Column('boolean')booleanMySQL实际存储为TINYINT(1)
DATETIME@Column('datetime')Date推荐使用TIMESTAMP自动管理时间
DECIMAL@Column('decimal', { precision: 10, scale: 2 })string避免使用float处理精确计算
JSON@Column('json')object自动序列化/反序列化

21. 关联关系实战

实现用户与文章的1对多关系:

// user.entity.ts @OneToMany(() => Article, (article) => article.author) articles: Article[]; // article.entity.ts @ManyToOne(() => User, (user) => user.articles) @JoinColumn({ name: 'author_id' }) author: User;

查询关联数据的几种方式:

  1. 使用relations选项:
this.usersRepository.find({ relations: ['articles'] });
  1. 使用查询构建器:
this.usersRepository .createQueryBuilder('user') .leftJoinAndSelect('user.articles', 'articles') .where('user.id = :id', { id: 1 }) .getOne();
  1. 使用@RelationId获取外键:
@RelationId((article: Article) => article.author) authorId: number;

22. 自定义仓储模式

扩展默认Repository功能:

// src/users/users.repository.ts @EntityRepository(User) export class UsersRepository extends Repository<User> { async findActiveUsers(): Promise<User[]> { return this.find({ where: { isActive: true } }); } } // 在模块中注册 @Module({ imports: [TypeOrmModule.forFeature([User, UsersRepository])], providers: [UsersService], controllers: [UsersController], }) export class UsersModule {} // 在服务中使用 @Injectable() export class UsersService { constructor( @InjectRepository(User) private usersRepository: UsersRepository, ) {} }

23. 数据库健康检查

实现全面的健康检查端点:

@Get('health') async healthCheck() { const dbCheck = await this.checkDatabase(); const redisCheck = await this.checkRedis(); return { status: dbCheck && redisCheck ? 'healthy' : 'degraded', details: { database: dbCheck ? 'up' : 'down', redis: redisCheck ? 'up' : 'down', timestamp: new Date().toISOString(), }, }; } private async checkDatabase(): Promise<boolean> { try { await this.usersRepository.query('SELECT 1'); return true; } catch { return false; } }

24. 连接池监控与管理

高级连接池配置示例:

TypeOrmModule.forRoot({ // ...其他配置 extra: { poolSize: 20, acquireTimeout: 30000, idleTimeout: 10000, queueLimit: 0, enableKeepAlive: true, keepAliveInitialDelay: 10000, }, }),

监控连接池状态的实用方法:

@Injectable() export class DatabaseMonitorService { constructor(private connection: Connection) {} getPoolStats() { const pool = this.connection.driver.pool; return { total: pool.totalCount, idle: pool.idleCount, waiting: pool.waitingCount, max: pool.options.connectionLimit, }; } }

25. 生产环境部署清单

上线前必须检查的项目:

  1. 安全配置

    • 禁用synchronize
    • 启用SSL连接
    • 使用强密码和最小权限账户
  2. 性能配置

    • 优化连接池大小
    • 设置适当的查询超时
    • 配置慢查询日志
  3. 监控配置

    • 实现健康检查端点
    • 设置数据库性能监控
    • 配置告警规则
  4. 备份策略

    • 定期全量备份
    • 二进制日志增量备份
    • 测试恢复流程
  5. 灾难恢复

    • 多可用区部署
    • 故障转移演练
    • 回滚方案准备

26. 性能基准测试

使用Jest进行简单的性能测试:

describe('Performance Tests', () => { it('should handle 100 concurrent queries', async () => { const start = Date.now(); const promises = Array(100) .fill(0) .map(() => usersService.findAll()); await Promise.all(promises); const duration = Date.now() - start; console.log(`100 queries took ${duration}ms`); expect(duration).toBeLessThan(1000); }); });

关键性能指标参考值:

操作类型单次操作预期耗时并发能力
简单查询<10ms1000+ QPS
复杂联查50-100ms100+ QPS
插入操作20-50ms500+ QPS
更新操作30-60ms300+ QPS

27. 连接泄漏排查

检测和修复连接泄漏的步骤:

  1. 监控连接数增长:
setInterval(() => { const pool = connection.driver.pool; console.log(`Connections: ${pool.totalCount}/${pool.options.connectionLimit}`); }, 1000);
  1. 使用AsyncLocalStorage跟踪连接获取:
import { AsyncLocalStorage } from 'async_hooks'; const connectionStorage = new AsyncLocalStorage(); async function withConnection<T>(fn: () => Promise<T>): Promise<T> { return connectionStorage.run(new Date(), async () => { try { return await fn(); } finally { const start = connectionStorage.getStore(); if (start && Date.now() - start > 1000) { console.warn('Long running connection detected'); } } }); }
  1. 常见泄漏场景:
    • 未处理异常的异步操作
    • 忘记释放的手动事务
    • 循环中未关闭的游标

28. 多租户实现

使用TypeORM实现多租户架构:

// 租户感知的Repository @EntityRepository(User) export class TenantAwareRepository extends Repository<User> { async findForTenant(tenantId: string): Promise<User[]> { return this.createQueryBuilder('user') .where('user.tenantId = :tenantId', { tenantId }) .getMany(); } } // 请求作用域的租户ID @Injectable({ scope: Scope.REQUEST }) export class TenantService { tenantId: string; } // 在服务中使用 @Injectable() export class UsersService { constructor( @InjectRepository(User) private usersRepository: TenantAwareRepository, private tenantService: TenantService, ) {} async findAll(): Promise<User[]> { return this.usersRepository.findForTenant(this.tenantService.tenantId); } }

29. 地理空间数据处理

MySQL支持的地理空间功能示例:

@Entity() export class Place { @PrimaryGeneratedColumn() id: number; @Column('point') location: string; @Column() name: string; } // 查询附近的点 async findNearby(lat: number, lng: number, radius: number) { return this.placesRepository .createQueryBuilder() .where( `ST_Distance_Sphere(location, ST_GeomFromText('POINT(${lng} ${lat})')) <= :radius`, { radius }, ) .getMany(); }

30. 全文搜索实现

使用MySQL全文索引:

@Entity() export class Article { @PrimaryGeneratedColumn() id: number; @Column() @Index({ fulltext: true }) title: string; @Column('text') @Index({ fulltext: true }) content: string; } // 全文搜索查询 async searchArticles(keyword: string) { return this.articlesRepository .createQueryBuilder() .where( `MATCH(title, content) AGAINST(:keyword IN BOOLEAN MODE)`, { keyword: `+${keyword}*` }, ) .getMany(); }

31. 数据加密方案

敏感字段加密策略:

import { encrypt, decrypt } from './crypto.util'; @Entity() export class User { @Column({ transformer: { to: (value: string) => encrypt(value), from: (value: string) => decrypt(value), }, }) privateKey: string; }

加密工具示例:

// src/shared/utils/crypto.util.ts import * as crypto from 'crypto'; const algorithm = 'aes-256-cbc'; const key = crypto.scryptSync(process.env.ENCRYPTION_KEY, 'salt', 32); const iv = Buffer.alloc(16, 0); export function encrypt(text: string): string { const cipher = crypto.createCipheriv(algorithm, key, iv); let encrypted = cipher.update(text, 'utf8', 'hex'); encrypted += cipher.final('hex'); return encrypted; } export function decrypt(encrypted: string): string { const decipher = crypto.createDecipheriv(algorithm, key, iv); let decrypted = decipher.update(encrypted, 'hex', 'utf8'); decrypted += decipher.final('utf8'); return decrypted; }

32. 数据库版本控制

使用Flyway管理数据库变更:

  1. 安装Flyway CLI
  2. 创建迁移脚本目录结构
  3. 编写SQL迁移文件:
-- V1__Initial_schema.sql CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL ); -- V2__Add_email_column.sql ALTER TABLE users ADD COLUMN email VARCHAR(255);
  1. 集成到Nest应用生命周期:
@Injectable() export class FlywayService { async migrate() { const flyway = new Flyway({ url: process.env.DATABASE_URL, user: process.env.DATABASE_USER, password: process.env.DATABASE_PASSWORD, locations: ['filesystem:./migrations'], }); await flyway.migrate(); } } // 在main.ts中调用 async function bootstrap() { const app = await NestFactory.create(AppModule); await app.get(FlywayService).migrate(); await app.listen(3000); }

33. 读写分离实战

配置读写分离连接:

TypeOrmModule.forRootAsync({ name: 'write', useFactory: () => ({ type: 'mysql', host: process.env.DB_WRITE_HOST, // ...写库配置 }), }), TypeOrmModule.forRootAsync({ name: 'read', useFactory: () => ({ type: 'mysql', host: process.env.DB_READ_HOST, // ...读库配置 }), }),

使用装饰器选择数据源:

@Injectable() export class UsersService { constructor( @InjectRepository(User, 'write') private writeRepository: Repository<User>, @InjectRepository(User, 'read') private readRepository: Repository<User>, ) {} async readOperations() { return this.readRepository.find(); } async writeOperations() { return this.writeRepository.save(new User()); } }

34. 连接失败重试策略

实现健壮的重连机制:

async function createConnectionWithRetry(options: ConnectionOptions, maxRetries = 3) { let retries = 0; while (retries < maxRetries) { try { return await createConnection(options); } catch (error) { retries++; if (retries === maxRetries) throw error; await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, retries)) ); console.log(`Retrying connection (attempt ${retries})...`);

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询