
你有没有遇到过DBA队友将生成环境与开发测试环境设置的不一样而导致的线上问题的案例?本人就遇到过一次:明明测试环境跑得好好的,一上生产就“原地爆炸”。
今天我们就来复盘一下因MySQL参数sql_generate_invisible_primary_key导致的问题,顺便把整个排查和复盘过程分享出来,帮大家避坑!
一、问题现象
未经审核的脚本发布到线上,监控告警就炸了:核心业务接口报错率飙升至 80%,用户反馈无法提交订单、查询数据。打开应用日志,满屏都是类似的错误:
### Error updating database. Cause: java.sql.SQLSyntaxErrorException: Unknown column 'my_row_id' in 'field list'
### The error may exist in com/xxx/mapper/OrderMapper.java (best guess)
### The error occurred while setting parameters
### SQL: INSERT INTO t_order (order_no, user_id, amount) VALUES (?, ?, ?)
### Cause: java.sql.SQLSyntaxErrorException: Unknown column 'my_row_id' in 'field list'奇怪的是:
二、排查过程:从代码到数据库的 “抽丝剥茧”
1. 核对代码与表结构
先核对了测试环境的表结构,t_order的建表语句确实没有my_row_id字段:
CREATE TABLE `t_order` (
`order_no` varchar(64) NOT NULL COMMENT '订单号',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`amount` decimal(10,2) NOT NULL COMMENT '订单金额'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';代码里的插入SQL也只涉及order_no、user_id、amount三个字段,完全没提my_row_id。
查看生产环境的表结构:
mysql> show create table t_order\G
*************************** 1. row ***************************
Table: t_order
Create Table: CREATE TABLE `t_order` (
`my_row_id` bigint unsigned NOT NULL AUTO_INCREMENT /*!80023 INVISIBLE */,
`order_no` varchar(64) NOT NULL COMMENT '订单号',
`user_id` bigint NOT NULL COMMENT '用户ID',
`amount` decimal(10,2) NOT NULL COMMENT '订单金额',
PRIMARY KEY (`my_row_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='订单表'
1 row in set (0.00 sec)

发现了根源。
2. 核对数据库配置差异
既然代码和表结构都没问题,那大概率是数据库配置的问题。对比测试库和生产库的参数,发现生产库多了一个关键配置:
-- 生产库配置
show variables like 'sql_generate_invisible_primary_key';
+-----------------------------------+-------+
| Variable_name | Value |
+-----------------------------------+-------+
| sql_generate_invisible_primary_key | ON |
+-----------------------------------+-------+
-- 测试库配置
show variables like 'sql_generate_invisible_primary_key';
+-----------------------------------+-------+
| Variable_name | Value |
+-----------------------------------+-------+
| sql_generate_invisible_primary_key | OFF |
+-----------------------------------+-------+
就是这个sql_generate_invisible_primary_key参数,直接锁定了问题根源!
3. 修复处理
建议将这个参数关闭,保持和开发测试环境的默认值一致。完毕后再将表加上业务主键。
此事件提醒大家:
三、GIPK 到底是什么?为什么会生成my_row_id?
sql_generate_invisible_primary_key全称是Generated Invisible Primary Key(自动生成隐藏主键),是MySQL8.0.30+为了帮开发者偷懒新增的特性,官方文档定义得非常明确:
四、 总结
技术坑不可怕,可怕的是踩了之后不总结。希望这个案例能帮大家避开MySQL这个 “隐形陷阱”,也提醒各位:线上环境的每一个参数配置,都值得反复核对!SQL脚本上线前一定要提供审核,避免有无主键的表!