• Redis的使用


    资料来自
    全部操作方法
    nodejs操作redis总结
    ioredis-lua
    redis-lua

    插件

    npm install redis 
    

    使用

    // redis配置参数
    let redis_config = {
        "host": "127.0.0.1",
        "port": 6379
    };
     
    let password = '';     //密码
    let dbs = {};
    const redis = require("redis");
    const client = redis.createClient(redis_config);
    if (password) {
        client.auth(password);
    }
    client.on("error", err => console.log('------ Redis connection failed ------' + err))
    client.on('connect', () => console.log('------ Redis connection succeed ------'));
    
    // 下面的方法应该写在connect的回调里
    
    client.set('hello','This is a value');
    client.expire('hello',10) //设置过期时间
    client.exists('key') //判断键是否存在
    client.del('key1')
    client.get('hello');
    

    常用方法

    //stirng
    命令 行为 返回值 使用示例(略去回调函数)
    set 设置存储在给定键中的值 OK set('key', 'value')
    get 获取存储在给定键中的值 value/null get('key')
    del 删除存储在给定键中的值(任意类型) 1/0 del('key')
    incrby 将键存储的值加上整数increment incrby('key', increment)
    decrby 将键存储的值减去整数increment decrby('key', increment)
    incrbyfloat 将键存储的值加上浮点数increment incrbyfloat('key', increment) 
    append 将值value追加到给定键当前存储值的末尾 append('key', 'new-value')
    getrange 获取指定键的index范围内的所有字符组成的子串 getrange('key', 'start-index', 'end-index')
    setrange 将指定键值从指定偏移量开始的子串设为指定值 setrange('key', 'offset', 'new-string')
    
    //list
    命令 行为 返回值 使用示例(略去回调函数)
    rpush 将给定值推入列表的右端 当前列表长度 rpush('key', 'value1' [,'value2']) (支持数组赋值)
    lrange 获取列表在给定范围上的所有值 array lrange('key', 0, -1) (返回所有值)
    lindex 获取列表在给定位置上的单个元素 lindex('key', 1)
    lpop 从列表左端弹出一个值,并返回被弹出的值 lpop('key')
    rpop 从列表右端弹出一个值,并返回被弹出的值 rpop('key')
    ltrim 将列表按指定的index范围裁减 ltrim('key', 'start', 'end')
     
    //set
    命令 行为 返回值 使用示例(略去回调函数) sadd 将给定元素添加到集合 插入元素数量 sadd('key', 'value1'[, 'value2', ...]) (不支持数组赋值)(元素不允许重复)
    smembers 返回集合中包含的所有元素 array(无序) smembers('key')
    sismenber 检查给定的元素是否存在于集合中 1/0 sismenber('key', 'value')
    srem 如果给定的元素在集合中,则移除此元素 1/0 srem('key', 'value')
    scad 返回集合包含的元素的数量 sacd('key') 
    spop 随机地移除集合中的一个元素,并返回此元素 spop('key')
    smove 集合元素的迁移 smove('source-key'dest-key', 'item')
    sdiff 返回那些存在于第一个集合,但不存在于其他集合的元素(差集) sdiff('key1', 'key2'[, 'key3', ...]) 
    sdiffstore 将sdiff操作的结果存储到指定的键中 sdiffstore('dest-key', 'key1', 'key2' [,'key3...]) 
    sinter 返回那些同事存在于所有集合中的元素(交集) sinter('key1', 'key2'[, 'key3', ...])
    sinterstore 将sinter操作的结果存储到指定的键中 sinterstore('dest-key', 'key1', 'key2' [,'key3...]) 
    sunion 返回那些至少存在于一个集合中的元素(并集) sunion('key1', 'key2'[, 'key3', ...])
    sunionstore 将sunion操作的结果存储到指定的键中 sunionstore('dest-key', 'key1', 'key2' [,'key3...]) //hash
    命令 行为 返回值 使用示例(略去回调函数)
    hset 在散列里面关联起给定的键值对 1(新增)/0(更新) hset('hash-key', 'sub-key', 'value') (不支持数组、字符串)
    hget 获取指定散列键的值 hget('hash-key', 'sub-key')
    hgetall 获取散列包含的键值对 json hgetall('hash-key')
    hdel 如果给定键存在于散列里面,则移除这个键 hdel('hash-key', 'sub-key')
    hmset 为散列里面的一个或多个键设置值 OK hmset('hash-key', obj)
    hmget 从散列里面获取一个或多个键的值 array hmget('hash-key', array)
    hlen 返回散列包含的键值对数量 hlen('hash-key')
    hexists 检查给定键是否在散列中 1/0 hexists('hash-key', 'sub-key')
    hkeys 获取散列包含的所有键 array hkeys('hash-key')
    hvals 获取散列包含的所有值 array hvals('hash-key')
    hincrby 将存储的键值以指定增量增加 返回增长后的值 hincrby('hash-key', 'sub-key', increment) (注:假如当前value不为为字符串,则会无输出,程序停止在此处)
    hincrbyfloat 将存储的键值以指定浮点数增加
     
    //zset 
    命令 行为 返回值 使用示例(略去回调函数)
    zadd 将一个带有给定分支的成员添加到有序集合中 zadd('zset-key', score, 'key') (score为int)
    zrange 根据元素在有序排列中的位置,从中取出元素
    zrangebyscore 获取有序集合在给定分值范围内的所有元素
    zrem 如果给定成员存在于有序集合,则移除
    zcard 获取一个有序集合中的成员数量 有序集的元素个数 zcard('key')
    
    // keys命令组
    命令 行为 返回值 使用示例(略去回调函数)
    del 删除一个(或多个)keys 被删除的keys的数量 del('key1'[, 'key2', ...])
    exists 查询一个key是否存在 1/0 exists('key')
    expire 设置一个key的过期的秒数 1/0 expire('key', seconds)
    pexpire 设置一个key的过期的毫秒数 1/0 pexpire('key', milliseconds) 
    expireat 设置一个UNIX时间戳的过期时间 1/0 expireat('key', timestamp)
    pexpireat 设置一个UNIX时间戳的过期时间(毫秒) 1/0 pexpireat('key', milliseconds-timestamp)
    persist 移除key的过期时间 1/0 persist('key')
    sort 对队列、集合、有序集合排序 排序完成的队列等 sort('key'[, pattern, limit offset count]) 
    flushdb 清空当前数据库
    

    事务,批量执行所有的命令,并统一返回结果

    client.multi()
       .set('xiao','xing')
       .get('xiao')
       .exec(function(err,replies) {
          console.log(replies);         // [ 'OK', 'xing' ]
       })
    

    订阅发布模式
    redis的订阅发布模式可用来做类似kafka的消息推送;
    使用list + redis的订阅发布模式可以构建一个不错的消息队列;

    let sub = redis.createClient(6379, '127.0.0.1');   // 监听消费者
    let pub = redis.createClient(6379, '127.0.0.1');   // 生产者
    
    // 在sub开始监听时允许触发subscribe事件进行操作,类似连接数据库的connect事件
    sub.on('subscribe', function(channel, count) {
         console.log(`${channel}:${count}`);               //  test channel:1
         pub.publish('test channel', 'channel message test')
    })
    sub.on('message', function(channel, message) {
         console.log(`${channel}-message:${JSON.stringify(message)}`)    // test channel-message:"channel message test"
    })
    
    sub.subscribe('test channel');
    

    对整个redis的所有客户端操作进行监听
    monitor事件可以监听到redis收到的所有客户端命令

    client.monitor(function(err, res) {
         console.log(res);   // ok
    })
    client.on("monitor", function (time, args) {
         // 1556285641.395573: [ 'lindex', 'myset', '2' ]
         console.log(time + ": " + util.inspect(args));             
    });
    

    redis-lua

    • 封装方法
    // redis连接,本身不创建,由外部传入。
    const redisClient;
    
    let instance = {
      script : {
    
      }
    };
    
    // 用于记录已在redis缓存过的脚本sha码
    let bufferScript = {};
    
    /**
     * 抢红包动作的脚本定义(keysLength值为KEY的个数)
     * KEYS[1]      计数器key
     * KEYS[2]      用户已抢到红包key
     * ARGV[1]      红包数额
     * ARGV[2]      limit
     * @return 1 成功  -1 失败1
     */
    instance.script.grabbingRedPacket = {
      code : `
        if(redis.call('xxx', KEYS[1]) < tonumber(ARGV[2]))
        then
          if(redis.call('xxx', KEYS[2], ARGV[1]) == 1)
          then
            return 1
          end
        else
          return -1
        end
      `,
      keysLength : 2
    };
    
    /**
     * lua执行器 自动判断是否已经缓存过  从而决定是向redis传递脚本还是sha
     * @param name    本脚本所支持的指令  位于 instance.script 下
     * @param ...param  该指令所期待的参数, 按照KEYS到ARGV的顺序罗列
     */
    instance.run = function(name, ...param) {
      return new Promise((resolve, reject) => {
        if (!redisClient) {
          reject('redisClient is no ready');
        } else if (!instance.script[name]) {
          reject('this command is not supported');
        } else {
          if (bufferScript[name]) {
            redisClient.evalsha(bufferScript[name], instance.script[name].keysLength, ...param, (err, result) => {
              if (err) {
                reject(err);
              } else {
                resolve(result);
              }
            });
          } else {
            redisClient.script('load', instance.script[name].code, (err, sha) => {
              if (err) {
                reject(err);
              } else {
                bufferScript[name] = sha;
                redisClient.evalsha(sha, instance.script[name].keysLength, ...param, (err, result) => {
                  if (err) {
                    reject(err);
                  } else {
                    resolve(result);
                  }
                });
              }
            });
          }
        }
      });
    }
    
    module.exports = function(client) {
      if (!client) {
        return;
      }
      redisClient = client;
      return instance;
    }
    
    • 使用
    const redis = require('redis');
    const client = redis.createClient(config.REDIS_PORT, config.REDIS_HOST, config.REDIS_OPTIONS);
    // 传入一个redis连接即可
    const luaScript = require('xxx/lua-script')(client);
    // 不需要关心这个脚本keys的数量, luaScript已经帮助实现了这个逻辑, 直接罗列命令期望的参数即可。
    luaScript.run('grabbingRedPacket',
        counterKey,
        userKey,
        amount,
        limit
      ).then(res => {
        ...
    });
    

    ioredis-lua,看起来比redis好,支持了await,官网

    • 下载
    npm install ioredis
    
    • eval
    const Redis = require("ioredis");
    const redis = new Redis(6379, "127.0.0.1");
    
    const evalScript = `return redis.call('SET', KEYS[1], ARGV[2])`;
    
    redis.defineCommand("evalTest", {
        numberOfKeys: 2,
        lua: evalScript,
    })
    
    async function eval() {
        await redis.evalTest('name1', 'name2', 'val1', 'val2');
        const result = await redis.get('name1');
        console.log(result); // val2
    }
    
    eval();
    
    • evalSHA
    const Redis = require("ioredis");
    const redis = new Redis(6379, "127.0.0.1");
    
    const evalScript = `return redis.call('SET', KEYS[1], ARGV[2])`;
    
    async function evalSHA() {
        // 1. 缓存脚本获取 sha1 值
        const sha1 = await redis.script("load", evalScript);
        console.log(sha1); // 6bce4ade07396ba3eb2d98e461167563a868c661
    
        // 2. 通过 evalsha 执行脚本
        await redis.evalsha(sha1, 2, 'name1', 'name2', 'val1', 'val2');
    
        // 3. 获取数据
        const result = await redis.get("name1");
        console.log(result); // "val2"
    }
    
    evalSHA();
    
    • 如果要使用独立的lua文件
    -- 先 SET
    redis.call("SET", KEYS[1], ARGV[1])
    redis.call("SET", KEYS[2], ARGV[2])
    
    -- GET 取值
    local key1 = tonumber(redis.call("GET", KEYS[1]))
    local key2 = tonumber(redis.call("GET", KEYS[2]))
    
    -- 如果 key1 小于 key2 返回 0
    -- nil 相当于 false
    if (key1 == nil or key2 == nil or key1 < key2) 
    then 
        return 0
    else 
        return 1
    end
    
    const Redis = require("ioredis");
    const redis = new Redis(6379, "127.0.0.1");
    const fs = require('fs');
    
    async function test() {
        const redisLuaScript = fs.readFileSync('./test.lua');
        const result1 = await redis.eval(redisLuaScript, 2, 'name1', 'name2', 20, 10);
        const result2 = await redis.eval(redisLuaScript, 2, 'name1', 'name2', 10, 20);
        console.log(result1, result2); // 1 0
    }
    
    test();
    
  • 相关阅读:
    看到关于java资料比较全的,自己收藏
    ie6下pnghack——css方案
    git基本操作
    购物车功能实现
    jquery学习:获取位置position(),offset(),scrollTop困惑
    Datax3.0使用说明
    Scala字符串操作
    Scala中class、object、case class、case object区别
    Scala构造函数
    scala数组操作
  • 原文地址:https://www.cnblogs.com/pengdt/p/13070879.html
Copyright © 2020-2023  润新知