Skip to content

Nest 中使用 Redis ​

本文重点解释 ioredis 的安装与使用,以及如何在 Nest 中使用 ioredis。

ioredis ​

我这里使用的是 yml 配置文件

安装 ioredis 类库 ​

ts
pnpm install ioredis --save

创建一个全局模块 redis ​

  • 代码
ts
nest g resource redis

修改这个模块 ​

  • (1) 删除控制器 redis.controller.ts

  • (2) 修改 redis.module.ts

ts
// redis.module.ts
import { Module, Global } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { Redis } from "ioredis";
import { RedisService } from "./redis.service.js";

@Global()
@Module({
  providers: [
    {
      provide: "REDIS_CLIENT",
      useFactory: (configService: ConfigService) => {
        const redis = new Redis({
          // Redis 服务器主机地址,默认 localhost
          host: configService.get<string>("REDIS_HOST", "localhost"),
          // Redis 服务器端口,默认 6379
          port: configService.get<number>("REDIS_PORT", 6379),
          // Redis 认证密码
          password: configService.get<string>("REDIS_PASSWORD"),
          // 使用的数据库索引,默认 0
          db: configService.get<number>("REDIS_DB", 0),
          // 使用 IPv4 协议
          family: 4,
          // 延迟连接:调用 connect() 时才真正建立连接,避免启动时阻塞
          lazyConnect: true,
          // 连接超时时间:10 秒
          connectTimeout: 10000,
          // 重试策略:每次重试间隔递增 1 秒,最多 10 秒
          retryStrategy: (times) => Math.min(times * 1000, 10000),
          // 单条命令最大重试次数
          maxRetriesPerRequest: 3,
          // key 前缀,用于命名空间隔离,防止 key 冲突
          keyPrefix: configService.get<string>("REDIS_PREFIX", ""),
        });

        redis.on("connect", () => console.log("[Redis] connecting..."));
        redis.on("ready", () => console.log("[Redis] ready"));
        redis.on("error", (err) => console.error("[Redis] error:", err));
        redis.on("close", () => console.warn("[Redis] connection closed"));
        redis.on("reconnecting", () => console.log("[Redis] reconnecting..."));

        return redis;
      },
      inject: [ConfigService],
    },
    RedisService,
  ],
  exports: [RedisService],
})
export class RedisModule {}
  • (3) 修改 redis.service.ts(env 配置)
ts
import { Inject, Injectable, OnModuleDestroy } from "@nestjs/common";
import { Redis } from "ioredis";
import { ConfigService } from "@nestjs/config";

@Injectable()
export class RedisService implements OnModuleDestroy {
  constructor(
    @Inject("REDIS_CLIENT") private readonly redis: Redis,
    private readonly configServiceAll: ConfigService,
  ) {}

  async onModuleDestroy() {
    await this.redis.quit();
  }

  // Redis获取所有的keys(使用 SCAN 避免阻塞)
  async getAllKeys(pattern: string = "*"): Promise<string[]> {
    const keys: string[] = [];
    let cursor = "0";
    do {
      const [nextCursor, foundKeys] = await this.redis.scan(
        cursor,
        "MATCH",
        pattern,
        "COUNT",
        100,
      );
      cursor = nextCursor;
      keys.push(...foundKeys);
    } while (cursor !== "0");
    return keys;
  }

  // Redis 获取单个key的值
  async get(key: string): Promise<string | null> {
    return await this.redis.get(key);
  }

  // 删除
  async delkey(key: string): Promise<number> {
    return await this.redis.del(key);
  }

  // 字符串方法 data 里面 有key ,value,ttl(可选)
  async setstr(data: { key: string; value: string }, ttl?: number) {
    const expiration =
      ttl || this.configServiceAll.get<number>("REDIS_TTL", 3600);
    await this.redis.set(data.key, data.value, "EX", expiration);
    return { [data.key]: data.value };
  }

  // -------------哈希只能一级。要是嵌套太多 就转成字符串 --------------------

  async sethash(key: string, data: Record<string, any>, ttl?: number) {
    const pipeline = this.redis.pipeline();
    for (const [field, value] of Object.entries(data)) {
      pipeline.hset(key, field, value);
    }
    const expiration =
      ttl || this.configServiceAll.get<number>("REDIS_TTL", 3600);
    pipeline.expire(key, expiration);
    await pipeline.exec();
    return this.gethash(key);
  }

  async gethash(key: string): Promise<Record<string, string>> {
    return await this.redis.hgetall(key);
  }

  // ---------------- 列表设置 ------------
  async setlist(key: string, data: any[], ttl?: number) {
    const pipeline = this.redis.pipeline();
    for (const item of data) {
      pipeline.rpush(key, item);
    }
    const expiration =
      ttl || this.configServiceAll.get<number>("REDIS_TTL", 3600);
    pipeline.expire(key, expiration);
    await pipeline.exec();
    return this.getlist(key);
  }

  //-------------列表获取----------
  async getlist(key: string): Promise<string[]> {
    return await this.redis.lrange(key, 0, -1);
  }
}

使用 ​

控制器 ​

ts
import { Controller, Post, Body } from "@nestjs/common";
import { UserService } from "./user.service";

@Controller("user")
export class UserController {
  constructor(private readonly userService: UserService) {}

  // 查询所有的key
  @Post("getallkeys")
  async getallkeys() {
    const result = await this.userService.getAllKeys();
    console.log(result);
    return {
      data: result,
    };
  }

  // 查看匹配的keys
  @Post("getcheckkeys")
  async getcheckkeys(@Body() body: any) {
    const params = body.value;
    console.log(params);
    const result = await this.userService.getcheckkeys(params);
    console.log(result);
    return {
      data: result,
    };
  }

  // 删除指定的key
  @Post("delkey")
  async delkey(@Body() body: any) {
    const params = body.value;
    console.log(params);
    const result = await this.userService.delkey(params);
    let message = "";
    if (result == 1) {
      message = "删除成功";
    }
    return {
      data: {
        message,
      },
    };
  }

  // ------------- 字符串-------------------
  // 设置字符串
  @Post("setstr")
  async setstr(@Body() body: any) {
    const value = body.value;
    const key = body.key;
    const result = await this.userService.setstr({ key, value });
    console.log(result);
    return {
      data: result,
    };
  }

  // 获取字符串
  @Post("getstr")
  async getstr(@Body() body: any) {
    const key = body.key;
    const result = await this.userService.getstr(key);
    console.log(result);
    return {
      data: result,
    };
  }

  // -------------对象Hash开始---------------
  @Post("sethash")
  async sethash(@Body() body: any) {
    const hashresult = { key: "hash1", value: { ...body } };
    const result = await this.userService.sethash(
      hashresult.key,
      hashresult.value,
    );
    console.log(result);
    return {
      data: result,
    };
  }

  // --------获取hash------
  @Post("gethash")
  async gethash(@Body() body: any) {
    const key = body.key;
    const result = await this.userService.getallhash(key);
    console.log(result);
    return {
      data: result,
    };
  }

  // -------------列表---------------
  @Post("setlist")
  async setlist(@Body() body: any) {
    console.log(body);
    const listresult = { key: "list1", value: [...body.list1] };
    const result = await this.userService.setlist(
      listresult.key,
      listresult.value,
    );
    console.log(result);
    return {
      data: result,
    };
  }

  // --------列表获取------------
  @Post("getlist")
  async getlist(@Body() body: any) {
    const key = body.key;
    const result = await this.userService.getlist(key);
    console.log(result);
    return {
      data: result,
    };
  }
}

services ​

ts
import { Inject, Injectable } from "@nestjs/common";
import { RedisService } from "../redis/redis.service";
import { ConfigService } from "@nestjs/config";
import { JwtServiceAll } from "../jwt/jwt.service";
// 数据库
import { PrismadbService } from "../prisma/prisma.service";
@Injectable()
export class UserService {
  // 注入配置文件
  @Inject()
  private readonly configService: ConfigService;
  // 注入Redis
  @Inject()
  private readonly redisService: RedisService;
  // 注入jwt
  @Inject()
  private readonly jwtService: JwtServiceAll;
  // 注入数据库
  @Inject()
  private readonly prismadbService: PrismadbService;
  // 获取所有的keys
  async getAllKeys() {
    const result = await this.redisService.getAllKeys();
    return result;
  }

  // 获取所有匹配的keys
  async getcheckkeys(data: string) {
    const result = await this.redisService.getAllKeys(data);
    return result;
  }

  // 删除指定的key
  async delkey(data: string) {
    const result = await this.redisService.delkey(data);
    return result;
  }

  // 字符串方法设置
  async setstr(data: Object) {
    const result: any = await this.redisService.setstr(data);
    return result;
  }

  // 字符串方法获取
  async getstr(data: string) {
    const result: any = await this.redisService.getstr(data);
    return result;
  }

  /*------------------设置hash------------------------*/

  async sethash(key: string, data: Object) {
    const result: any = await this.redisService.sethash(key, data);
    return result;
  }

  // 获取所有的hash
  async getallhash(key: string) {
    const result: any = await this.redisService.gethash(key);
    return result;
  }

  // ---------列表-------------------
  async setlist(key: string, data: any[]) {
    const result: any = await this.redisService.setlist(key, data);
    return result;
  }

  async getlist(key: string) {
    const result: any = await this.redisService.getlist(key);
    return result;
  }
}