当前位置: 首页 > 工具软件 > koa-redis > 使用案例 >

koa2中使用redis(Typescript版本)

西门山
2023-12-01

最近公司某个项目涉及到了视频直播的模块,看了网上许多案例都是基于rtmp或hls的方案进行直播的,考虑到日后chrome不再支持flash,于是试着结合MSE和node中间层进行直播流的推送和解析操作,其中就涉及到了node操作redis的环节。

一、配置ORM库

一般来说,无论服务端还是中间层,针对mysql和mongoDB这种数据库都会使用ORM进行操作,redis也一样,因此在开始使用redis之前,我们首先应该下载好一个提供ORM操作层的第三方包,我这里选择了ioredis这个库:(当然,前提是本地已经安装好了redis并且成功开启,具体教程这里就不阐述了)

npm install ioredis

二、编写配置文件

编写配置文件是为了免去每次进行数据库操作或连接数据库都重写porthost等参数的麻烦,而且尽可能地保持“一库一连”,即全局连接一次,处处都运用这个实例进行读写,这样可以最大限度保证性能。
本人的redis工具配置目录如下:

--redis
 |--redisConnection.ts  //连接逻辑
 |--redisOperate.ts  //数据库操作逻辑

考虑到生产与开发的环境不同,连接redis的端口和地址也不同,建议为两个环境各自写一个config。
redisConnection.ts 内容如下:

    import * as ioredis from 'ioredis';
import { resolve } from 'dns';

interface redisConfig {
    port:number,
    host:string,
    password?:string
    db?:number //连接的数据库id,默认为0,即第一个数据库
    family?:number //可填参数:4、6 (ipv4\ipv6)
}

let clientCreate = (config:redisConfig,callback_:Function) => {
    let redis:ioredis.Redis = new ioredis(config);
    redis.on('connect',()=>{ //根据 connect 事件判断连接成功
        callback_(null,redis) //链接成功, 返回 redis 连接对象
    })
    redis.on('error',(err)=>{ //根据 error 事件判断连接失败
        callback_(err,null) //捕捉异常, 返回 error
    })
}

let redisConn = (options?:redisConfig) => {
    let config = options
    return new Promise((resolve,reject) => { //返回API调用方 一个 promise 对象
        clientCreate(config,(err:any,conn:ioredis.Redis) => {
            if(err) {
                reject(err)
            }
            resolve(conn) //返回连接的redis对象
        })
    })
}

export default redisConn

这样就完成了一个连接redis的通用实例了,这样做的好处是可操作空间大,也利于后续封装

三、编写读写操作文件

由于ioredis这个第三方库的很多操作返回都是Promise对象,如果直接在项目里使用很容易会造成回调过多的情况,因此封装成async/await的方式会更利于开发,那么我们可以这样来编写redisOperate.ts文件:

import redisConnect from './redisConnection'
import * as ioredis from 'ioredis'
import getConfig from '../../config/index';

export interface redisTool {
    setString(key:string,value:any):Promise<string|void>
    getString(key:any):Promise<string>
    delString(key:string):Promise<number|null>
    getDbSize():Promise<number>
    connToRedis():Promise<unknown>
}

interface redisConfig {
    port:number,
    host:string,
    password?:string
    db?:number
    family?:number
}

const env = process.env.NODE_ENV;
let redisConfig:redisConfig = {
    port: getConfig(env).port_redis,
    host: getConfig(env).host_redis
}

class RedisTool implements redisTool {
    redis:ioredis.Redis
    config:redisConfig
    constructor(opt?:any){
      this.redis = null;
        if(opt){
            this.config = Object.assign(redisConfig,opt)
        }else{
            this.config = redisConfig
        }
        // this.connToRedis()
      this.connToRedis().then(res=>{
          if(res){
              console.log('redis connet success')
          }
      }).catch(e=>{
          console.error('The Redis Can not Connect:'+e)
      })
    }

    /**连接redis */
    connToRedis(){
        return new Promise((resolve, reject) => {  
            if(this.redis) {
                resolve(true) //已创建
            } else {
                redisConnect(this.config).then((resp:ioredis.Redis) =>  { 
                    this.redis = resp
                    resolve(true) }
                ).catch(err => { reject(err) })
            }
        })
    }

    /**存储string类型的key-value */
    async setString(key:string,value:any){
        let val:string = typeof(value)!=='string'?JSON.stringify(value):value;
        let k:string = typeof(value)!=='string'?JSON.stringify(key):key;
        try {
            const res = await this.redis.set(k, val);
            return res;
        }
        catch (e) {
            console.error(e);
        }
    }

    /**获取string类型的key-value */
    async getString(key:any){
        let id:string = typeof(key)!=='string'?JSON.stringify(key):key;
        try{
            const res = await this.redis.get(id);
            return res
        }catch(e){
            console.error(e);
            return null
        }
    }

    /**删除string类型的key-value */
    async delString(key:string){
        let id:string = typeof(key)!=='string'?JSON.stringify(key):key;
        try{
            const res =  await this.redis.del(id);
            return res
        }catch(e){
            console.error(e);
            return null
        }
    }

    /**获取当前数据库key的数量 */
    async getDbSize(){
        try{
            const res = await this.redis.dbsize();
            return res
        }catch(e){
            console.error(e);
            return null
        }
    }

}

export const default_redis = new RedisTool();
/*
需要用到多少个数据库,就定义多少个实例常量,这样的好处是:
每次个模块调用redis的时候,始终是取第一次生成的实例,避免了多次连接redis的尴尬
*/
export const redis_db1 = new RedisTool({db:1})
// export const redis_db2 = new RedisTool({db:2})
// export const redis_db3 = new RedisTool({db:3})
// export const redis_db4 = new RedisTool({db:4})

export default default_redis

四、使用方法实例

当我们把所有redis配置和操作层逻辑都封装好之后,就可以在任意需要用到的redis直接使用生成的实例了,比如在某一模块下进行读写操作:

import {default_redis} from '../../utils/redis/redisOperate' 
//引入我们编写好的操作逻辑文件,导出我们提前生成好的redis实例
let redisTool_db0 = default_redis

const test = async (str:string):Promise<void> => {
    let key:string = str;
    let res:string = await redisTool_db.setString(key,'这是存入的value')
    if(res!==null){console.log('写入成功')}
    else{console.log('写入失败')}
    let res2:string = await redisTool_db.getString(key)
    if(res2!==null){console.log('读取成功,value是:'+ res2)}
    else{console.log('读取失败')}
}

test('hello')
//打印
//写入成功
//读取成功,value是:这是存入的value

 类似资料: