用 MySQL SELECT SLEEP() 优雅模拟网络超时与并发死锁

你写了一个接口,配置了 MyBatis 的查询超时时间为 3 秒(readTimeout=3000)。
测试痛点: 怎么验证这个超时配置生效了?

  • 笨办法: 造几千万条数据,写一个巨复杂的 SQL 让它跑慢点。
  • 土办法: 写个断点,手动卡住程序,或者让运维去把数据库网线拔了。
  • 优雅办法: 改一下 SQL,注入一个 SLEEP(5)。

SELECT SLEEP() 是 MySQL 的内置函数,它能让当前的 SQL 执行线程"睡眠"指定的秒数。这在测试系统的健壮性、连接池配置以及并发锁机制时,好用到爆炸。


1. 核心原理:让数据库"睡"一会儿

语法非常简单:

sql 复制代码
SELECT SLEEP(N);
  • 参数 N: 暂停的秒数(支持小数,如 0.5)。
  • 返回值: 正常结束后返回 0。
  • 效果: 假如执行 SELECT SLEEP(3),MySQL 线程会挂起 3 秒,这期间该连接是被占用的。

2. 四大实战场景

场景一:验证应用层的 Timeout 配置

这是最常用的场景。我们需要验证 Spring Boot / JDBC 是否能正确处理数据库超时异常。

测试 SQL:

sql 复制代码
-- 假设业务查询是查用户
SELECT * FROM users WHERE id = 1 AND SLEEP(5);

预期结果:

如果你的应用层配置了 socketTimeout=3000 (3秒),那么 3 秒后,你的 Java 程序应该捕获到 SocketTimeoutException 或 MySQLTimeoutException,而不是傻傻地等 5 秒。

场景二:测试连接池 (Connection Pool) 的抗压能力

背景: 当数据库查询变慢时,连接池很容易被占满,导致整个系统不可用(雪崩效应)。
测试方案:

利用 JMeter 或 Apache Benchmark 开启 50 个线程,并发请求一个执行 SELECT SLEEP(10) 的接口。
观察:

如果你的连接池最大连接数 (maxActive) 设置为 20。你会发现前 20 个请求进去了,后面的请求会开始排队(Waiting),最终报错"Get connection timeout"。
目的: 验证连接池满载时的降级策略和报警机制是否生效。

场景三:复现并发锁与死锁 (Locking & Deadlock)

背景: 有些并发 Bug 只有在两个事务"同时"执行时才会出现。但在本地调试时,代码跑得太快,很难手动模拟"同时"。
技巧: 用 SLEEP 强行延长事务持有锁的时间。

事务 A (模拟长事务):

sql 复制代码
BEGIN;
UPDATE products SET stock = stock - 1 WHERE id = 100;
-- 强行持有锁 20 秒,给事务 B 制造机会
SELECT SLEEP(20); 
COMMIT;

事务 B (测试被阻塞):

在事务 A 睡觉的 20 秒内,启动事务 B 去更新同一行,观察是否会被阻塞(Block)或超时。

场景四:安全攻防中的"时间盲注" (Time-based Blind SQLi)

这是黑客最喜欢的场景,也是开发者必须防范的。
背景: 某些接口即使报错也不会回显错误信息(Blind),黑客无法知道 SQL 是否注入成功。
攻击手段:
http://api.com/user?id=1 AND SLEEP(5)
判断标准:

  • 如果接口 立即返回,说明没有注入漏洞(输入被过滤了)。
  • 如果接口 卡了 5 秒才返回 ,说明 SLEEP(5) 被执行了,注入成功!

3. 避坑指南 (Danger Zone)

虽然 SLEEP 好用,但它在生产环境是危险品。

  1. 严禁在生产环境业务代码中使用:
    万一你手抖把 SLEEP(1) 写进了线上代码,只要 QPS 稍微高一点,数据库连接池瞬间就会被占满,直接导致全站宕机(Denial of Service)。
  2. WHERE 子句中的陷阱:
    注意!SLEEP 是每行执行一次!
sql 复制代码
-- 假设 users 表有 1000 行
SELECT * FROM users WHERE id > 0 AND SLEEP(1);

后果: 并不是睡 1 秒,而是睡 1000 x 1 = 1000 秒 !MySQL 会扫描每一行,对每一行都执行一次睡眠。这绝对是毁灭级的。

  1. 主从复制延迟:

基于 Statement 格式的 Binlog 复制,会将 SLEEP 语句同步到从库执行。主库睡了 10 秒,从库回放时也要睡 10 秒,导致主从延迟瞬间飙升。


4. 总结

SELECT SLEEP() 是后端开发者的"混沌工程"入门工具。

  • 用它测试超时: 验证你的代码会不会在网络抖动时挂起。
  • 用它测试并发: 它是复现死锁和竞态条件的神器。
  • 小心使用: 别在全表扫描的 WHERE 里用它,否则你就要去写事故报告了。
相关推荐
灰原喜欢柯南1 分钟前
OceanBase 运维管理知识点——OCP 监控、诊断与变更控制
数据库·oceanbase
码农-0042 分钟前
Springboot 集成 Ehcache操作数据库显示SQL语句设置
数据库·spring boot·sql
仍然.4 分钟前
Redis---事务
数据库·redis
oradh5 分钟前
Oracle 执行计划的阅读方法(二叉树结构来理解和阅读)
数据库·oracle·执行计划的阅读方法
SelectDB8 分钟前
Doris 向量检索上线踩坑记录:七个排查现场与可直接复制的命令
大数据·数据库·数据分析
数据库小学妹9 分钟前
MySQL深分页优化:LIMIT大偏移的根因分析与五种解法对比
数据库·mysql·性能优化
SelectDB10 分钟前
一条大查询把集群打挂之后:Apache Doris 稳定性处置与资源隔离速查
大数据·数据库·数据分析
这个DBA有点耶10 分钟前
数据库部署架构深潜:集中式、分布式、云原生的技术原理、演进逻辑与选型框架
数据库·架构
鸽芷咕12 分钟前
MySQL 数据库管理工具用惯了?切金仓数据库,这篇帮你把家伙事儿配齐
数据库