当前位置: 首页 > article >正文

nestjs 连接redis

1、安装

npm i ioredis

2、创建redisService(其实就是定义了一个类,把new Redis返回的实例进行了绑定 然后导出)

import { ConfigService } from "@nestjs/config";
import Redis from "ioredis";
export class RedisService {
    private redisClient: any;
    constructor(private readonly configService: ConfigService) {
        this.redisClient = new Redis({
            host: configService.get("redis.host"),
            port: configService.get("redis.port"),
            db: configService.get("redis.db"),
            password: configService.get("redis.password"),
            // 设置重连次数
            retryStrategy: (times: number) => {
                if (times > 3) {
                    return null;
                }
            }
        })
    }
    // 当模块销毁时
    OnModuleDestroy() {
        // 断开连接
        this.redisClient.quit()
    }
    getClient() {
        return this.redisClient
    }

    /* --------------------- string 相关 -------------------------- */

    /**
     *
     * @param key 存储 key 值
     * @param val key 对应的 val
     * @param ttl 可选,过期时间,单位 毫秒
     */
    async set(key: string, val: any, ttl?: number): Promise<'OK' | null> {
        const data = JSON.stringify(val);
        if (!ttl) return await this.redisClient.set(key, data);
        return await this.redisClient.set(key, data, 'PX', ttl);
    }

    async mget(keys: string[]): Promise<any[]> {
        if (!keys) return [];
        const list = await this.redisClient.mget(keys);
        return list.map((item) => JSON.parse(item));
    }

    /**
     * 返回对应 value
     * @param key
     */
    async get(key: string): Promise<any> {
        if (!key || key === '*') return null;
        const res = await this.redisClient.get(key);
        return JSON.parse(res);
    }

    async del(keys: string | string[]): Promise<number> {
        if (!keys || keys === '*') return 0;
        if (typeof keys === 'string') keys = [keys];
        return await this.redisClient.del(...keys);
    }

    async ttl(key: string): Promise<number | null> {
        if (!key) return null;
        return await this.redisClient.ttl(key);
    }

    /**
     * 获取对象keys
     * @param key
     */
    async keys(key?: string) {
        return await this.redisClient.keys(key);
    }

    /* ----------------------- hash ----------------------- */

    /**
     * hash 设置 key 下单个 field value
     * @param key
     * @param field 属性
     * @param value 值
     */
    async hset(key: string, field: string, value: string): Promise<string | number | null> {
        if (!key || !field) return null;
        return await this.redisClient.hset(key, field, value);
    }

    /**
     * hash 设置 key 下多个 field value
     * @param key
     * @param data
     * @params expire 单位 秒
     */
    async hmset(key: string, data: Record<string, string | number | boolean>, expire?: number): Promise<number | any> {
        if (!key || !data) return 0;
        const result = await this.redisClient.hmset(key, data);
        if (expire) {
            await this.redisClient.expire(key, expire);
        }
        return result;
    }

    /**
     * hash 获取单个 field 的 value
     * @param key
     * @param field
     */
    async hget(key: string, field: string): Promise<number | string | null> {
        if (!key || !field) return 0;
        return await this.redisClient.hget(key, field);
    }

    /**
     * hash 获取 key 下所有field 的 value
     * @param key
     */
    async hvals(key: string): Promise<string[]> {
        if (!key) return [];
        return await this.redisClient.hvals(key);
    }

    async hGetAll(key: string): Promise<Record<string, string>> {
        return await this.redisClient.hgetall(key);
    }
    /**
     * hash 删除 key 下 一个或多个 fields value
     * @param key
     * @param fields
     */
    async hdel(key: string, fields: string | string[]): Promise<string[] | number> {
        if (!key || fields.length === 0) return 0;
        return await this.redisClient.hdel(key, ...fields);
    }

    /**
     * hash 删除 key 下所有 fields value
     * @param key
     */
    async hdelAll(key: string): Promise<string[] | number> {
        if (!key) return 0;
        const fields = await this.redisClient.hkeys(key);
        if (fields.length === 0) return 0;
        return await this.hdel(key, fields);
    }

    /* -----------   list 相关操作 ------------------ */

    /**
     * 获取列表长度
     * @param key
     */
    async lLength(key: string): Promise<number> {
        if (!key) return 0;
        return await this.redisClient.llen(key);
    }

    /**
     * 通过索引设置列表元素的值
     * @param key
     * @param index
     * @param val
     */
    async lSet(key: string, index: number, val: string): Promise<'OK' | null> {
        if (!key || index < 0) return null;
        return await this.redisClient.lset(key, index, val);
    }

    /**
     * 通过索引获取 列表中的元素
     * @param key
     * @param index
     */
    async lIndex(key: string, index: number): Promise<string | null> {
        if (!key || index < 0) return null;
        return await this.redisClient.lindex(key, index);
    }

    /**
     * 获取列表指定范围内的元素
     * @param key
     * @param start 开始位置, 0 是开始位置
     * @param stop 结束位置, -1 返回所有
     */
    async lRange(key: string, start: number, stop: number): Promise<string[] | null> {
        if (!key) return null;
        return await this.redisClient.lrange(key, start, stop);
    }

    /**
     * 将一个或多个值插入到列表头部
     * @param key
     * @param val
     */
    async lLeftPush(key: string, ...val: string[]): Promise<number> {
        if (!key) return 0;
        return await this.redisClient.lpush(key, ...val);
    }

    /**
     * 将一个值或多个值插入到已存在的列表头部
     * @param key
     * @param val
     */
    async lLeftPushIfPresent(key: string, ...val: string[]): Promise<number> {
        if (!key) return 0;
        return await this.redisClient.lpushx(key, ...val);
    }

    /**
     * 如果 pivot 存在,则在 pivot 前面添加
     * @param key
     * @param pivot
     * @param val
     */
    async lLeftInsert(key: string, pivot: string, val: string): Promise<number> {
        if (!key || !pivot) return 0;
        return await this.redisClient.linsert(key, 'BEFORE', pivot, val);
    }

    /**
     * 如果 pivot 存在,则在 pivot 后面添加
     * @param key
     * @param pivot
     * @param val
     */
    async lRightInsert(key: string, pivot: string, val: string): Promise<number> {
        if (!key || !pivot) return 0;
        return await this.redisClient.linsert(key, 'AFTER', pivot, val);
    }

    /**
     * 在列表中添加一个或多个值
     * @param key
     * @param val
     */
    async lRightPush(key: string, ...val: string[]): Promise<number> {
        if (!key) return 0;
        return await this.redisClient.lpush(key, ...val);
    }

    /**
     * 为已存在的列表添加一个或多个值
     * @param key
     * @param val
     */
    async lRightPushIfPresent(key: string, ...val: string[]): Promise<number> {
        if (!key) return 0;
        return await this.redisClient.rpushx(key, ...val);
    }

    /**
     * 移除并获取列表第一个元素
     * @param key
     */
    async lLeftPop(key: string): Promise<string> {
        if (!key) return '';
        const result = await this.redisClient.blpop(key);
        return result.length > 0 ? result[0] : '';
    }

    /**
     * 移除并获取列表最后一个元素
     * @param key
     */
    async lRightPop(key: string): Promise<string> {
        if (!key) return '';
        const result = await this.redisClient.brpop(key);
        return result.length > 0 ? result[0] : '';
    }

    /**
     * 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除
     * @param key
     * @param start
     * @param stop
     */
    async lTrim(key: string, start: number, stop: number): Promise<'OK' | null> {
        if (!key) return null;
        return await this.redisClient.ltrim(key, start, stop);
    }

    /**
     * 移除列表元素
     * @param key
     * @param count
     * count > 0 :从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count;
     * count < 0 :从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值;
     * count = 0 : 移除表中所有与 value 相等的值
     * @param val
     */
    async lRemove(key: string, count: number, val: string): Promise<number> {
        if (!key) return 0;
        return await this.redisClient.lrem(key, count, val);
    }

    /**
     * 移除列表最后一个元素,并将该元素添加到另一个裂膏并返回
     * 如果列表没有元素会阻塞队列直到等待超时或发现可弹出元素为止
     * @param sourceKey
     * @param destinationKey
     * @param timeout
     */
    async lPoplPush(sourceKey: string, destinationKey: string, timeout: number): Promise<string> {
        if (!sourceKey || !destinationKey) return '';
        return await this.redisClient.brpoplpush(sourceKey, destinationKey, timeout);
    }

    /**
     * 删除全部缓存
     * @returns
     */
    async reset() {
        const keys = await this.redisClient.keys('*');
        return this.redisClient.del(keys);
    }
}

3、全局注入

就是用工厂函数实例化RedisService,然后导出

import { Global, Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
import configurationService from '../config/index';
import { join } from 'path';
import { ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler';
import { APP_GUARD } from '@nestjs/core';
import { JwtModule } from '@nestjs/jwt';
import { JwtAuthGuard } from '../utils/auth/jwt-auth.guard';
import { JwtAuthStrategy } from '../utils/auth/jwt-auth.strategy';
import { RedisService } from 'src/utils/redisService';
@Global()
@Module({
    imports: [
        ConfigModule.forRoot({
            cache: true,
            load: [configurationService],
            isGlobal: true,
        }),
        TypeOrmModule.forRootAsync({
            inject: [ConfigService],
            useFactory: (config: ConfigService) => {
                return ({
                    type: "mysql",
                    autoLoadEntities: true,     //自动加载实体
                    timezone: '+08:00',
                    ...config.get("db.mysql"),
                } as TypeOrmModuleOptions)
            }
        }),
        JwtModule.registerAsync({
            inject: [ConfigService],
            useFactory: (config: ConfigService) => {
                return {
                    secret: config.get("jwt.secretkey"),
                    signOptions: {
                        expiresIn: config.get("jwt.expiresin"),
                    },
                }
            }
        }),
        ThrottlerModule.forRoot([
            {
                name: 'short',
                ttl: 1000,
                limit: 1,
            }
        ])
    ],
    providers: [
        JwtAuthStrategy,
        {
            provide: APP_GUARD,
            useClass: ThrottlerGuard,
        },
        {
            provide: APP_GUARD,
            useClass: JwtAuthGuard,
        },
        {
            provide: RedisService,
            inject: [ConfigService],
            useFactory: (config: ConfigService) => {
                return new RedisService(config)
            },
        }
    ],
    exports: [
        TypeOrmModule,
        JwtAuthStrategy,
        JwtModule,
        RedisService
    ],
})
export class ShareModule { }

4、使用

import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

import { RedisService } from 'src/utils/redisService';
@Injectable()
export class UsersService {
  constructor(
    private readonly redisService: RedisService
  ) { }
  async create(createUserDto: CreateUserDto) {
    await this.redisService.set("测试",1);
    const test = await this.redisService.get("测试");
    return test;
  }

  findAll() {
    return `This action returns all users`;
  }

  findOne(id: number) {
    return `This action returns a #${id} user`;
  }

  update(id: number, updateUserDto: UpdateUserDto) {
    return `This action updates a #${id} user`;
  }

  remove(id: number) {
    return `This action removes a #${id} user`;
  }
}


http://www.kler.cn/a/612147.html

相关文章:

  • 数据可视化(matplotlib)-------图表样式美化
  • 蓝桥杯第十届 数的分解
  • Linux——进程信号(1)(signal与sigaction)
  • java程序员实用英语学习总结
  • linux scp复制多层级文件夹到另一服务器免密及脚本配置
  • 【深度学习与实战】2.1、线性回归模型与梯度下降法先导
  • [250324] Kafka 4.0.0 版本发布:告别 ZooKeeper,拥抱 KRaft!| Wine 10.4 发布!
  • Apache Shiro 全面指南:从入门到高级应用
  • 网络安全可以去哪些单位工作
  • Windows 图形显示驱动开发-WDDM 2.7功能-MCDM KM 驱动程序实现指南(三)
  • Anaconda 安装NCL (Linux系统)
  • ArcGIS字段计算器的详细使用案例
  • 机器学习核心评估指标解析:AUC-ROC、RMSE、轮廓系数与PR AUC详解
  • 深度解析 | Android 12系统级禁用SIM卡功能实现与Framework层定制
  • 城电科技 | 光伏植物墙 一款会发电发光自动浇水的植物墙
  • STM32八股【2】-----ARM架构
  • OpenHarmony子系统开发 - init启动引导组件(七)
  • 在Windows docker desktop 中安装Dify
  • Android Studio编译问题
  • 单元测试mock