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做缓存

应用程序与MySQL和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:

运行结果:

测试MySQL与Redis联动

在Redis中查询:

8.3.4 模拟缓存穿透现象

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

工程结构如下:

cache/student.go:

biz/student.go:

controller/student.go:

运行结果:

测试访问MySQL中不存在的数据

在Redis中查询:

8.3.5 模拟内存使用不当的场景

在之前的程序中,由于没有设置超时时间,因此所有的key都将永久存在于Redis中.持续这样发展下去,一定会遇到内存OOM的时刻.因此,在使用Redis的场景中,需要合理设置缓存数据的超时时间.这不是一个可选项,而是必选项.

此处我的实现思路为:

  • 写入时设置过期时间

  • 读取时重置过期时间

  • 若某个key在过期时间内都未被读取,则任由其到达过期时间后被淘汰

工程结构如下:

cache/student.go:

其他文件均未改变

连续访问2次后,在Redis中查看指定key的生命周期:

Last updated