使用Gorm操作MariaDB插入titles表触发Error 1022错误求助
咱们一步步拆解你遇到的问题:明明手动执行SQL能成功,但用Gorm插入就报Can't write; duplicate key in table 'titles',已经排除了外键名称重复的情况,那大概率是Gorm的行为差异或者触发器的隐藏冲突,下面是具体的排查方向和解决方案:
一、先确认Gorm实际生成的SQL和手动执行的是否一致
这是最关键的一步,因为Gorm的ORM封装可能会悄悄修改你传入的参数或者自动添加字段,导致生成的SQL和你手动写的不一样。
你可以在Gorm里开启Debug模式执行插入,比如:
db.Debug().Create(&yourTitleModel)
然后查看控制台打印的SQL语句,和你手动在Navicat里执行的SQL做对比,重点看:
- 有没有多出来的字段(比如模型里定义了表中没有的字段,Gorm自动添加了默认值)
- 字段值是否和你传入的一致(比如
anime_id是int类型,但Gorm传了字符串?不过MariaDB通常会自动转换,但也可能有例外) - 有没有重复赋值同一个字段的情况
如果发现Gorm生成的SQL和手动的不一样,那问题就出在这里,你需要调整模型定义,比如用gorm:"-"忽略多余字段,或者确保字段类型和表结构完全匹配。
二、检查触发器导致的间接冲突
你的trigger_hash_gen触发器会在插入titles后往title_hashtags表插入数据,虽然错误提示指向titles,但有可能是触发器执行时的冲突被关联到了原表操作上。
你可以先手动执行触发器里的判断逻辑,看看是否已经存在冲突记录:
SELECT * FROM title_hashtags WHERE hashtag_value = TRIM(BOTH '_' FROM REGEXP_REPLACE('Urashimasakatasen no Nichijou Special', '[^a-zA-Z0-9]+','_'));
如果查询到已有记录,那说明触发器插入时会冲突,但错误提示可能因为是触发器触发的,所以指向了titles表。
这时候你需要修改触发器,因为当前触发器只判断hashtag_value是否存在,但不同的anime_id可能会生成相同的hashtag_value,正确的判断应该是同时检查anime_id和hashtag_value的组合:
DROP TRIGGER IF EXISTS `trigger_hash_gen`; DELIMITER ;; CREATE TRIGGER `trigger_hash_gen` AFTER INSERT ON `titles` FOR EACH ROW IF NOT EXISTS (SELECT * FROM title_hashtags WHERE anime_id = NEW.anime_id AND hashtag_value = TRIM(BOTH '_' FROM REGEXP_REPLACE(NEW.anime_name, '[^a-zA-Z0-9]+','_'))) THEN INSERT INTO title_hashtags(anime_id, hashtag_value) VALUES (NEW.anime_id, TRIM(BOTH '_' FROM REGEXP_REPLACE(NEW.anime_name, '[^a-zA-Z0-9]+','_'))); END IF ;; DELIMITER ;
三、验证Gorm执行原生SQL的情况
你可以直接用Gorm执行你手动写的INSERT语句,看看是否会报错:
sql := `INSERT INTO \`titles\` (\`anime_id\`,\`anime_name\`,\`anime_name_rus\`,\`pidor_ban\`,\`vk_new_template_sub\`,\`vk_new_template_dub\`,\`video_name_template_sub\`,\`video_name_template_dub\`,\`video_desc_template_sub\`,\`video_desc_template_dub\`,\`telegram_new_template_sub\`,\`telegram_new_template_dub\`,\`telegram_sub_group_id\`,\`telegram_dub_group_id\`,\`vk_banned\`,\`vk_sub_group_id\`,\`vk_dub_group_id\`,\`vk_album_id_sub\`,\`vk_album_id_dub\`,\`default_sub_add_att\`,\`default_dub_add_att\`,\`gdrive_parent_id\`,\`gdrive_torrent_id\`,\`gdrive_sub_id\`,\`gdrive_font_id\`,\`anime_shiki_id\`,\`anime_name_jpn\`,\`anime_rating\`,\`anime_episodes\`,\`subscribe_sub_enabled\`,\`subscribe_dub_enabled\`,\`subscribe_priority\`,\`sub_purse\`,\`dub_purse\`,\`sub_qiwi\`,\`dub_qiwi\`,\`sub_paypal\`,\`dub_paypal\`,\`ai_search_enabled\`,\`nyaa_scan_enabled\`) VALUES ('1046','Urashimasakatasen no Nichijou Special','Деньки Урасимасакатасэн: Школьная пора — Эпизод 13','0','','','','','','','','','0','0','0','0','0','56053731','56053731','','','1-SHGDPX_ybF0Kqu0rtLKcnY_rmfsXa96','1WmRjv8fsZAAY2uBGoRx76Ar1B8rJGKcj','1TvlCnAQ6DbLR3WWiePDCJerYNEwX09oW','1nZRP4Yf92DyuyeOPtW44_vzZLENN6gs6','40921','','','0','0','0','0','0','0','','','','','0','0')` result := db.Exec(sql) if result.Error != nil { fmt.Println(result.Error) }
如果执行原生SQL不报错,那说明是Gorm的Create方法自动填充了某些字段导致的冲突,你需要检查模型定义里的字段标签,比如有没有设置gorm:"default:xxx"但实际表中的默认值不同,或者模型里有多余的字段被自动赋值了。
四、排除数据库连接不一致的情况
确认Gorm连接的数据库和你手动操作的是同一个库,比如有时候测试环境和生产环境的数据库搞混了,导致Gorm插入的库已经有重复的anime_id,而你手动操作的是另一个库。
内容的提问来源于stack exchange,提问作者Александр Подорин

