MySQL存储过程循环必须先DECLARE变量、游标、处理器,再写逻辑;变量需初始化防NULL失效;WHILE需显式步进防死循环;批量操作须加事务控制大小并避免循环内查总数。
DECLARE变量声明必须在BEGIN之后、逻辑之前
MySQL要求所有
语句必须紧接在
后,且必须在任何可执行语句(如
、
)之前。顺序错乱会直接报错
。
常见错误写法:
出现在
之前;或在
中间插入
语句。
正确顺序:先
所有变量、游标、异常处理器,再写逻辑
变量类型要匹配实际用途:计数器用
或
(避免
溢出导致循环提前终止)
未初始化的变量值为
,参与计算(如
)会导致整个表达式为
,循环失效
WHILE循环比REPEAT/LOOP更直观,但需手动控制步进
是最常用、最易理解的循环结构,适合“先判断后执行”场景,比如按数量批量插入或按ID范围更新。但它不会自动递增变量,必须显式写
,漏掉这句就会死循环。
示例中常见的陷阱:
条件写成
但初始值是
,结果执行100次而非99次——要核对边界是否符合业务预期
循环体末尾忘记
更新变量,尤其在嵌套
分支里容易遗漏
使用
拼接字符串时传入
字段,整条
变成
,插入静默失败(无报错但没数据)
批量插入时,每轮INSERT都是一次独立事务,性能差且易锁表
默认情况下,存储过程内每条
都是自动提交的(除非显式开启事务)。这意味着1000次循环 = 1000次磁盘写入 + 1000次行锁获取/释放,不仅慢,还可能阻塞其他读写操作。
MySQL(Linux)
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
下载
真正实用的批量处理必须加事务包裹:
开头加
,结尾加
若中途出错需回滚,加上
捕获异常并
注意:事务越大,undo log占用越多,单次循环建议控制在500~5000行,避免撑爆日志空间
不要在循环里反复查COUNT(*)或MAX(id)来控制边界
有些实现会在
条件中写
,每次循环都查一次——这在大数据量下极耗性能,且可能因并发写入导致边界漂移(比如两次查询之间有新数据插入)。
更稳妥的做法是:
一次性算好目标总数或最大ID,存入变量,后续只操作该变量
用主键范围分片(如
),避免
偏移带来的全表扫描
如果依赖动态条件(如“状态为待处理的数据”),应在循环外用临时表固化快照,否则每次查到的数据集可能不一致
真正卡住人的不是语法,而是循环边界怎么定、事务包多大、以及变量什么时候变
——这些细节不验证,过程能编译通过,但跑起来要么不动,要么删错数据。
DECLAREBEGINSETINSERTERROR 1337 (42000): Variable or condition declaration after cursor or handler declarationSET i = 0;DECLARE i INT DEFAULT 0;DECLARESELECTDECLAREINTBIGINTINTNULLi = i + 1NULLWHILESET i = i + 1;i <= 1001SETIFCONCAT()NULLVALUESNULLINSERTSTART TRANSACTION;COMMIT;DECLARE EXIT HANDLER FOR SQLEXCEPTIONROLLBACKWHILESELECT COUNT(*) INTO @cnt FROM t WHERE ...WHERE id BETWEEN @start AND @endLIMITNULL