你有没有遇到过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奇怪的是测试环境、预发环境完全正常只有生产库报这个错t_order表我们明明没定义my_row_id字段,代码里也没用到my_row_id为什么会报 “找不到my_row_id列”二、排查过程从代码到数据库的 “抽丝剥茧”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 订单金额) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单表;代码里的插入SQL也只涉及order_no、user_id、amount三个字段完全没提my_row_id。查看生产环境的表结构mysql show create table t_order\G*************************** 1. row *************************** Table: t_orderCreate 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)) ENGINEInnoDB AUTO_INCREMENT2 DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_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. 修复处理建议将这个参数关闭保持和开发测试环境的默认值一致。完毕后再将表加上业务主键。此事件提醒大家MySQL数据库的innodb表一定要加上主键新增的SQL上线前一定要进行审核开发、测试、生产环境等各个环境的各个参数和硬件相关的除外保持一致数据库一点要标准化建设三、GIPK 到底是什么为什么会生成my_row_idsql_generate_invisible_primary_key全称是Generated Invisible Primary Key自动生成隐藏主键是MySQL8.0.30为了帮开发者偷懒新增的特性官方文档定义得非常明确当该参数开启时MySQL会为没有显式定义主键的InnoDB表且即使表中已经有唯一索引也会生成自动添加一个名为my_row_id的隐藏列作为主键这个列类型为BIGINT UNSIGNED自增、不显式可见GIPK的my_row_id与InnoDB 底层的my_row_id有差异部分ORM框架、JDBC驱动会感知到这个隐藏字段甚至自动拼接进SQL因此会报错四、 总结技术坑不可怕可怕的是踩了之后不总结。希望这个案例能帮大家避开MySQL这个 “隐形陷阱”也提醒各位线上环境的每一个参数配置都值得反复核对SQL脚本上线前一定要提供审核避免有无主键的表关注我的微信公众号【数据库干货铺】后续分享更多数据库运维及优化干货避开各种开发坑
踩坑!MySQL这个参数让应用直接崩了,90%的DBA都忽略了!
你有没有遇到过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奇怪的是测试环境、预发环境完全正常只有生产库报这个错t_order表我们明明没定义my_row_id字段,代码里也没用到my_row_id为什么会报 “找不到my_row_id列”二、排查过程从代码到数据库的 “抽丝剥茧”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 订单金额) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单表;代码里的插入SQL也只涉及order_no、user_id、amount三个字段完全没提my_row_id。查看生产环境的表结构mysql show create table t_order\G*************************** 1. row *************************** Table: t_orderCreate 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)) ENGINEInnoDB AUTO_INCREMENT2 DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_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. 修复处理建议将这个参数关闭保持和开发测试环境的默认值一致。完毕后再将表加上业务主键。此事件提醒大家MySQL数据库的innodb表一定要加上主键新增的SQL上线前一定要进行审核开发、测试、生产环境等各个环境的各个参数和硬件相关的除外保持一致数据库一点要标准化建设三、GIPK 到底是什么为什么会生成my_row_idsql_generate_invisible_primary_key全称是Generated Invisible Primary Key自动生成隐藏主键是MySQL8.0.30为了帮开发者偷懒新增的特性官方文档定义得非常明确当该参数开启时MySQL会为没有显式定义主键的InnoDB表且即使表中已经有唯一索引也会生成自动添加一个名为my_row_id的隐藏列作为主键这个列类型为BIGINT UNSIGNED自增、不显式可见GIPK的my_row_id与InnoDB 底层的my_row_id有差异部分ORM框架、JDBC驱动会感知到这个隐藏字段甚至自动拼接进SQL因此会报错四、 总结技术坑不可怕可怕的是踩了之后不总结。希望这个案例能帮大家避开MySQL这个 “隐形陷阱”也提醒各位线上环境的每一个参数配置都值得反复核对SQL脚本上线前一定要提供审核避免有无主键的表关注我的微信公众号【数据库干货铺】后续分享更多数据库运维及优化干货避开各种开发坑