8.3 Redis与MySQL的整合
8.3.1 通过Docker安装MySQL开发环境
此处我直接用的本地MySQL.DDL语句如下:
CREATE TABLE `student` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`score` float DEFAULT NULL,
`created_at` datetime DEFAULT CURRENT_TIMESTAMP,
`updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;DML语句如下:
INSERT INTO `student` (`id`, `name`, `age`, `score`, `created_at`, `updated_at`)
VALUES
(1,'Peter',18,100,'2023-08-23 14:10:16','2023-08-23 14:10:16'),
(2,'Tom',17,98,'2023-08-23 14:10:27','2023-08-23 14:10:27'),
(3,'John',17,99,'2023-08-23 14:10:38','2023-08-23 14:10:38');8.3.2 通过GORM连接并操作MySQL数据库
本例中使用GIN + GORM + REDIGO这3个库来完成演示
8.3.2.1 初始化连接
工程结构如下:
cache/conf.go:
cache/conn.go:
db/conf.go:
db/conn.go:
main.go:
运行结果如下:
8.3.2.2 引入web框架
工程结构如下:
controller/student.go如下:
resp/response.go如下:
main.go如下:
运行结果如下:

8.3.3 引入Redis做缓存

本例中,我们使用Redis中的list类型缓存MySQL中的数据.其中:
key的命名规则为:
Stu + Id.例如:Stu1,Stu2,Stu3...value的结构为:
Stu[0]:id列Stu[1]:name列Stu[2]:age列Stu[3]:score列
整体思路如下:
step1. 根据id到Redis中查询,查询到则直接返回cache中的数据
step2. 未查询到则去MySQL中查询
step3. 将从MySQL中查询到的数据存入Redis
工程结构如下:
cache/student.go:
db/student.go:
biz/student.go:
request/student/getStudentById.go:
controller/student.go:
运行结果:

在Redis中查询:
8.3.4 模拟缓存穿透现象
上文中的程序已经实现了缓存数据的功能.但是还存在一个问题:假如接收到一个数据库中不存在的id,例如id=4.那么按上文中的代码,每次还是会去MySQL中查询,进而导致这些请求都从Redis缓存层"穿透"到MySQL数据库.这样一来MySQL还是需要应对高并发的压力.避免缓存穿透的解决方案:缓存不存在的数据
工程结构如下:
cache/student.go:
biz/student.go:
controller/student.go:
运行结果:

在Redis中查询:
8.3.5 模拟内存使用不当的场景
在之前的程序中,由于没有设置超时时间,因此所有的key都将永久存在于Redis中.持续这样发展下去,一定会遇到内存OOM的时刻.因此,在使用Redis的场景中,需要合理设置缓存数据的超时时间.这不是一个可选项,而是必选项.
此处我的实现思路为:
写入时设置过期时间
读取时重置过期时间
若某个key在过期时间内都未被读取,则任由其到达过期时间后被淘汰
工程结构如下:
cache/student.go:
其他文件均未改变
连续访问2次后,在Redis中查看指定key的生命周期:
Last updated