• 作者:老汪软件技巧
  • 发表时间:2024-09-05 17:01
  • 浏览量:

前言

入职快一周了,leader因为出差到现在也没见过,而mentor给我唯一的需求就是:学学redis和express(我记得我明明学的前端来着。。。)。

正文什么是redis

在学习一门技术之前首先最起码得搞明白这门技术有什么特点,是干什么的。

和大家耳熟能详的MySQL类似,redis也是数据库,更确切地说,redis和map数据类型很相似,是一种键值数据库,键名可以是对象,字符串,(有)无序集合等。

与MySQL最大的区别是,MySQL的数据存储在硬盘上,而redis数据则存储在内存上,这也就意味着redis的读取速度非常快,比MySQL快100倍甚至更多,快到可以提供微秒级别的读取速度。这里也有两个小demo可以用于MySQL以及redis的读取速度测试

Redis 读取速度测试

const Redis = require("ioredis");
const redis = new Redis();
async function testRedisSpeed() {
  const start = Date.now();
  for (let i = 0; i < 1000000; i++) {
    await redis.get(`key-${i}`);
  }
  const end = Date.now();
  const duration = end - start;
  console.log(`Redis read speed: ${1000000 / duration} ops/s`);
}
testRedisSpeed();

MySQL 读取速度测试

const mysql = require("mysql2");
async function testMySQLSpeed() {
  const connection = mysql.createConnection({
    host: "localhost",
    user: "root",
    password: "password",
    database: "testdb",
  });
  const start = Date.now();
  for (let i = 0; i < 1000000; i++) {
    await connection.query("SELECT * FROM test_table WHERE id = ?", [i]);
  }
  const end = Date.now();
  const duration = end - start;
  console.log(`MySQL read speed: ${1000000 / duration} ops/s`);
  connection.end();
}
testMySQLSpeed();

不仅如此,作为一个正儿八经的数据库,redis也支持通过RDB(Redis Database Backup)快照将数据持久化(也就是将数据从内存写入到硬盘中)。而不至于一关机内存条清空数据就全没有了。

在node.js中使用redis

相较于Java等多线程的后端语言,node使用数据库还是一如既往的简单轻松愉悦。相比于redis,这里更推荐ioredis,因为它提供了现代的API和更好的性能。安装ioredis并将其配置成Windows服务这里推荐一位大佬的文章Windows-Redis安装与配置 - 掘金 ()具体过程非常详细,这里就不做过多赘述了。

安装完成后就可以在项目中引入了,这里注意在实例化redis的时候,如果有密码的话需要将密码作为参数传入,否则会报错。在我推荐的文章中有临时密码和永久密码,这里非常建议设置永久密码并将其作为键值对在实例的过程中传入

const Redis = require("ioredis");
const redis = new Redis({
  password: "123456",
});

Redis基础

虽说在node环境中使用redis已经算是非常简单的了,但一套流程下来也得差不多半个小时了。完成以上步骤之后redis的安装以及配置就算是完成了,接下来就来到了令人鸡冻的敲代码时刻。首先先来熟悉一下redis中的数据类型,在redis中,常用的数据类型有以下几种:

// 设置缓存数据;
redis.set("user:123", JSON.stringify({ name: "John", age: 30 })); 
redis.set("user:456", JSON.stringify({ name: "Tom", age: 30 }));
// 获取缓存数据
redis.get("user:123").then((data) => {
  if (data) {
    const user = JSON.parse(data);
    console.log(user);
  } else {
    console.log("缓存不存在");
    // 如果缓存不存在,从后端数据库获取数据并更新缓存
  }
});
redis.get("user:456").then((data) => {
  if (data) {
    const user = JSON.parse(data);
    console.log(user);
  } else {
    console.log("缓存不存在");
  }
});
//删除user:123的值
redis.del("user:123", JSON.stringify({ name: "John", age: 30 })); 
redis.get("user:123").then((data) => {
  if (data) {
    const user = JSON.parse(data);
    console.log(user);
  } else {
    console.log("缓存不存在");
    // 如果缓存不存在,从后端数据库获取数据并更新缓存
  }
});

_query是什么意思_gemquery

redis.hset("user123", "name", "John");
redis.hset("user123", "age", "18");
redis
  .hgetall("user123")
  .then((hash) => {
    console.log(hash);
  })
  .catch((error) => {
    console.error("Error getting data:", error);
  });

我们可以用hash.getall方法去获取指定hash集合的所有键值对,当然也可以和下面一样通过hget方法获取某个指定的键值对

redis.hget("user123", "name").then((value) => {
  console.log(value);
});

当一个hash集合中拥有大量键值对的时候,按照上面的方法一个个hset是很折磨人的,所以也可以通过hmset去植入一个对象类型的值

redis
  .hmset("user234", {
    name: "Mike",
    age: "15",
    sex: "male",
  })
  .then((data) => {
    console.log("Hash set successfully");
  })
  .catch((err) => {
    console.error("Error:", err);
  });
redis
  .hgetall("user234")
  .then((hash) => {
    console.log(hash);
  })
  .catch((error) => {
    console.error("Error getting data:", error);
  });

redis
  .rpush("list-key", "item1", "item2", "item3", "item4", "item5")
  .then((count) => {
    console.log(`列表有 ${count} 个元素.`);
  })
  .catch((error) => {
    console.error("Error:", error);
  });

和数组不太一样的地方在于,列表不需要提前声明,而是直接通过rpush去往列表塞数组,当第一个参数(也就是列表名)所对应的列表不存在时,redis会自动创建它,然后再添加元素

// 获取列表长度
redis
 .llen("list-key")
 .then((length) => {
   console.log(`列表长度为: ${length}`);
 })
 .catch((error) => {
   console.error("Error:", error);
 });
// 从列表左侧弹出一个元素
redis
 .lpop("list-key")
 .then((item) => {
   console.log(`左侧弹出元素: ${item}`);
 })
 .catch((error) => {
   console.error("Error:", error);
 });
// 从列表右侧弹出一个元素
redis
 .rpop("list-key")
 .then((item) => {
   console.log(`右侧弹出元素: ${item}`);
 })
 .catch((error) => {
   console.error("Error:", error);
 });
// 获取列表中的一部分元素
redis
 .lrange("list-key", 0, -1)
 .then((items) => {
   console.log(`列表部分元素: ${items}`);
 })
 .catch((error) => {
   console.error("Error :", error);
 });
// 设置列表中的元素
redis
 .lset("list-key", 1, "new-item")
 .then((result) => {
   console.log(`设置结果: ${result}`);
 })
 .catch((error) => {
   console.error("Error:", error);
 });
// 移除列表中等于给定值的元素
redis
 .lrem("list-key", 1, "item2")
 .then((count) => {
   console.log(`移除 ${count} 元素.`);
 })
 .catch((error) => {
   console.error("Error:", error);
 });
// 截断列表
redis
 .ltrim("list-key", 0, 1)
 .then((result) => {
   console.log(`截断结果: ${result}`);
 })
 .catch((error) => {
   console.error("Error:", error);
 });

在 Redis 中,SET 是一种无序的、不重复的字符串集合。SET 类型非常适合用于存储具有唯一性的数据集合,例如一组用户的ID、一个网站的唯一访客列表等。下面,同样用一个demo去介绍set身上的一些常用方法

// 添加成员到集合
redis.sadd("users", "Alice", "Bob", "Charlie").then(count => {
  console.log(`Added ${count} new members.`);
});
// 获取集合中的所有成员
redis.smembers("users").then(members => {
  console.log(`Members: ${members}`);
});
// 检查成员是否存在
redis.sismember("users", "Alice").then(result => {
  console.log(`Alice is in the set: ${result ? "Yes" : "No"}`);
});
// 删除成员
redis.srem("users", "Bob").then(count => {
  console.log(`Removed ${count} members.`);
});
// 获取集合中成员的数量
redis.scard("users").then(count => {
  console.log(`Number of members: ${count}`);
});
// 交集
redis.sadd("groupA", "Alice", "Bob", "David");
redis.sadd("groupB", "Bob", "Charlie", "Eve");
redis.sinter("groupA", "groupB").then(intersection => {
  console.log(`Intersection: ${intersection}`);
});
// 并集
redis.sunion("groupA", "groupB").then(union => {
  console.log(`Union: ${union}`);
});
// 差集
redis.sdiff("groupA", "groupB").then(difference => {
  console.log(`Difference: ${difference}`);
});

与set不同的地方在于,zset多了一个排序的功能。zset的每个元素都有一个分数并根据分数进行排序

// 添加成员到有序集合
redis.zadd("scores", 85, "Alice", 92, "Bob", 78, "Charlie").then(count => {
  console.log(`Added ${count} new members.`);
});
// 获取排序后的成员
redis.zrange("scores", 0, -1, "WITHSCORES").then(range => {
  console.log(`Sorted range: ${range}`);
});
// 更新成员的分数
redis.zadd("scores", 90, "Alice").then(count => {
  console.log(`Updated Alice's score.`);
});
// 获取成员的分数
redis.zscore("scores", "Alice").then(score => {
  console.log(`Alice's score: ${score}`);
});
// 删除成员
redis.zrem("scores", "Charlie").then(count => {
  console.log(`Removed ${count} members.`);
});
// 获取有序集合中成员的数量
redis.zcard("scores").then(count => {
  console.log(`Number of members: ${count}`);
});
// 获取分数位于指定范围内的成员数量
redis.zcount("scores", 80, 90).then(count => {
  console.log(`Members with scores between 80 and 90: ${count}`);
});
// 获取指定成员的排名
redis.zrank("scores", "Bob").then(rank => {
  console.log(`Bob's rank: ${rank}`);
});
// 交集
redis.zadd("groupA", 85, "Alice", 92, "Bob", 78, "Charlie");
redis.zadd("groupB", 90, "Bob", 80, "Charlie", 95, "Eve");
redis.zinterstore("intersection", "groupA", "groupB").then(count => {
  console.log(`Intersected members: ${count}`);
});
// 并集
redis.zunionstore("union", "groupA", "groupB").then(count => {
  console.log(`Unioned members: ${count}`);
});

总结

以上便是一些redis的入门基础,后续我也会继续更新一些相关的内容,比如管道,事务等。最后祝各位读者姥爷0 waring(s),0 error(s)。