目录

简介

在现代化的 Web 应用中,数据库和缓存是必不可少的组件。本文将详细介绍如何在 NestJS 项目中集成 MySQL 和 Redis,包括配置、使用和最佳实践。

环境准备

在开始之前,请确保你的开发环境中已安装:

  • Node.js (推荐 v16+)
  • MySQL 8.0+
  • Redis 7.0+
  • Docker (可选,用于容器化部署)

MySQL 集成

安装依赖

首先,我们需要安装必要的依赖包:

bash 复制代码
pnpm add @nestjs/typeorm typeorm mysql2

配置数据库连接

  1. 创建配置文件 src/config/configuration.ts
typescript 复制代码
export default () => ({
  database: {
    host: process.env.DB_HOST || 'localhost',
    port: parseInt(process.env.DB_PORT, 10) || 3306,
    username: process.env.DB_USERNAME || 'root',
    password: process.env.DB_PASSWORD || 'root',
    database: process.env.DB_DATABASE || 'blog',
  },
});
  1. 创建数据库配置模块 src/config/database.config.ts
typescript 复制代码
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import { ConfigService } from '@nestjs/config';

export function getBaseDbConfig(configService: ConfigService) {
  return {
    type: 'mysql',
    host: configService.get('database.host'),
    port: configService.get('database.port'),
    username: configService.get('database.username'),
    password: configService.get('database.password'),
    database: configService.get('database.database'),
    timezone: '+08:00',
    charset: 'utf8mb4',
    logging: configService.get<boolean>('database.logging', false),
  };
}

export const createTypeOrmOptions = async (
  configService: ConfigService,
): Promise<TypeOrmModuleOptions> => {
  const baseConfig = getBaseDbConfig(configService);
  
  return {
    ...baseConfig,
    entities: [__dirname + '/../**/*.entity{.ts,.js}'],
    synchronize: process.env.NODE_ENV === 'development',
  };
};

创建实体

使用 TypeORM 装饰器创建实体类,例如用户实体:

typescript 复制代码
import { Entity, Column } from 'typeorm';
import { BaseEntity } from './base.entity';

@Entity('t_user')
export class User extends BaseEntity {
  @Column({ length: 50 })
  nickname: string;

  @Column({ length: 50, unique: true })
  username: string;

  @Column({ select: true })
  password: string;

  @Column({ nullable: true })
  avatar: string;
}

使用 TypeORM

在模块中配置 TypeORM:

typescript 复制代码
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { createTypeOrmOptions } from './config/database.config';

@Module({
  imports: [
    ConfigModule.forRoot({
      load: [configuration],
    }),
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: createTypeOrmOptions,
      inject: [ConfigService],
    }),
  ],
})
export class AppModule {}

Redis 集成

安装依赖

bash 复制代码
pnpm add ioredis

配置 Redis 服务

  1. 创建 Redis 服务 src/redis/redis.service.ts
typescript 复制代码
import { Injectable, Logger, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as Redis from 'ioredis';

@Injectable()
export class RedisService implements OnModuleInit, OnModuleDestroy {
  private readonly logger = new Logger(RedisService.name);
  private redisClient: Redis.Redis;

  constructor(private readonly configService: ConfigService) {}

  async onModuleInit() {
    try {
      this.redisClient = new Redis.Redis({
        host: this.configService.get('redis.host', 'localhost'),
        port: this.configService.get('redis.port', 6379),
        password: this.configService.get('redis.password', null),
        db: this.configService.get('redis.db', 0),
        retryStrategy: (times) => {
          const delay = Math.min(times * 50, 2000);
          return delay;
        },
      });

      this.redisClient.on('connect', () => {
        this.logger.log('Redis连接成功');
      });

      this.redisClient.on('error', (error) => {
        this.logger.error(`Redis连接错误: ${error.message}`);
      });
    } catch (error) {
      this.logger.error(`初始化Redis客户端失败: ${error.message}`);
    }
  }

  async onModuleDestroy() {
    await this.redisClient?.quit();
  }

  // Redis 操作方法
  async set(key: string, value: any, ttl?: number): Promise<void> {
    const stringValue = JSON.stringify(value);
    if (ttl) {
      await this.redisClient.setex(key, ttl, stringValue);
    } else {
      await this.redisClient.set(key, stringValue);
    }
  }

  async get(key: string): Promise<any> {
    const value = await this.redisClient.get(key);
    return value ? JSON.parse(value) : null;
  }

  async del(key: string): Promise<void> {
    await this.redisClient.del(key);
  }
}
  1. 创建 Redis 模块 src/redis/redis.module.ts
typescript 复制代码
import { Module } from '@nestjs/common';
import { RedisService } from './redis.service';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [ConfigModule],
  providers: [RedisService],
  exports: [RedisService],
})
export class RedisModule {}

使用 Redis 服务

在需要使用 Redis 的模块中:

typescript 复制代码
import { Module } from '@nestjs/common';
import { RedisModule } from '../redis/redis.module';
import { RedisService } from '../redis/redis.service';

@Module({
  imports: [RedisModule],
  providers: [YourService],
})
export class YourModule {
  constructor(private readonly redisService: RedisService) {}

  async someMethod() {
    // 存储数据
    await this.redisService.set('key', { data: 'value' }, 3600); // 1小时过期
    
    // 获取数据
    const data = await this.redisService.get('key');
    
    // 删除数据
    await this.redisService.del('key');
  }
}

Docker 部署

使用 Docker Compose 配置开发环境:

yaml 复制代码
version: '3'
services:
  mysql:
    image: mysql:8.0
    container_name: blog-mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_USER: ${DB_USERNAME}
      MYSQL_PASSWORD: ${DB_PASSWORD}
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql

  redis:
    image: redis:7.0
    container_name: blog-redis
    restart: always
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data

volumes:
  mysql_data:
  redis_data:

最佳实践

  1. 数据库连接管理

    • 使用连接池管理数据库连接
    • 实现重试机制处理连接失败
    • 在生产环境中禁用 synchronize 选项
  2. Redis 使用建议

    • 合理设置键的过期时间
    • 使用适当的数据结构(String、Hash、List、Set、Sorted Set)
    • 实现错误处理和重试机制
    • 监控 Redis 内存使用情况
  3. 安全性考虑

    • 使用环境变量管理敏感信息
    • 限制数据库用户权限
    • 配置 Redis 密码
    • 使用 SSL/TLS 加密连接
  4. 性能优化

    • 使用数据库索引
    • 实现适当的缓存策略
    • 监控查询性能
    • 定期清理过期数据

通过以上配置和实践,你可以在 NestJS 项目中高效地使用 MySQL 和 Redis,构建高性能、可扩展的应用程序。

评论
默认头像
评论
来发评论吧~