- 作者:老汪软件技巧
- 发表时间: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("缓存不存在");
// 如果缓存不存在,从后端数据库获取数据并更新缓存
}
});
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)。