今天线上项目报错了 500 错误,Laravel 日志中显示
Illuminate/Database/QueryException with message 'SQLSTATE[42S22]:
Column not found: 1054 Unknown column 'is_charge' in 'field list'
(SQL: update `some_categories` set `lft` = case when `lft` >= 29 then `lft`+2 else `lft` end, `rgt` = case when `rgt` >= 29 then `rgt`+2 else `rgt` end where (`lft` >= 29 or `rgt` >= 29))'
即新增层级菜单的时候,更新历史节点的 left right 值报错。
但是,报错很诡异,SQL 语句中并没有 is_charge 出现,但是却一直报
Column not found: 1054 Unknown column 'is_charge' in 'field list'
这个错误很常见,以往都是因为线上数据表表没有同步新增字段,引起字段缺失。但是,完全不相关的 SQL 语句怎么会报出这个错误呢?
排除 Laravel 的问题
为了排除是 Laravel 的三方依赖问题,我直接在 MySQL 命令行中执行测试:
mysql> update some_categories set is_charge = 1 where id = 241;
ERROR 1054 (42S22): Unknown column 'is_charge' in 'field list'
mysql> update some_categories set type = 1 where id = 241;
ERROR 1054 (42S22): Unknown column 'is_charge' in 'field list'
果然,都是同样的错误,这么简单的 SQL 语句都会报错,说明不是单纯的 SQL 拼写错误。
我猜测是这个表有 MySQL 的触发器。
排查 MySQL 的触发器
SELECT * FROM information_schema.TRIGGERS \G;
果然找到了对应的触发器
TRIGGER_CATALOG: def
TRIGGER_SCHEMA: db1
TRIGGER_NAME: some_categories_insert
EVENT_MANIPULATION: INSERT
EVENT_OBJECT_CATALOG: def
EVENT_OBJECT_SCHEMA: db1
EVENT_OBJECT_TABLE: some_categories
ACTION_ORDER: 1
ACTION_CONDITION: NULL
ACTION_STATEMENT: BEGIN INSERT INTO db2.some_categories (id,name,type,link,page_id,page_id,parent_id,lft,rgt,depth,image,created_at,updated_at,is_charge) VALUES (NEW.i$,NEW.name,NEW.type,NEW.link,NEW.page_id,NEW.parent_id,NEW.lft,NEW.rgt,NEW.depth,NEW.image,NEW.created_at,NEW.updated_at,NEW.is_charge);
END
问题很明显了,对应的同步数据库 db2 里的对应表,缺少了 is_charge 字段。确认了一下,确实如此。
问题解决。
参考:https://bugs.mysql.com/bug.php?id=68715
战斗还没有结束
新增字段之后,不报之前的错误了。但是又出现了一个新的错误。
[2019-05-13 22:47:49] production.ERROR: SQLSTATE[21S01]:
Insert value list does not match column list:
1136 Column count doesn't match value count at row 1
(SQL: insert into `some_categories` (`name`, `parent_id`, `lft`, `rgt`, `updated_at`, `created_at`) values (测试测试, 225, 29, 30, 2019-05-13 22:47:49, 2019-05-13 22:47:49))
Column count doesn't match value count 这个错误也很容易理解,就是字段名列表跟值列表个数不匹配。检查了 SQL 没有问题,看来又是触发器的问题了。
在 MySQL 命令行下做了验证,确实如此
mysql> insert into some_categories (name, `type`) values ('test', 1);
ERROR 1136 (21S01): Column count doesn't match value count at row 1
晚上实在太困,到了凌晨,效率更低,愣是没看出触发器那里写错了字段。我决定先睡觉去。。。
今天一早,瞬间发现 page_id,page_id 写了两遍。。。
去掉一个之后,就恢复正常了。
结论
- MySQL 排除 SQL 语句问题时,最好在 MySQL 命令行中进行。没有干扰。
- 触发器确实少用比较好,容易忘掉他的存在
- MySQL 的提示确实不够友好。没有注明是触发器中的问题。感觉想尝试其他数据库了。
- 凌晨排查问题效率太低,不能指望人肉排查
微信关注我哦 👍
我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式