Files
012-kaopeilian/知识库/知识点删除问题分析.md
111 998211c483 feat: 初始化考培练系统项目
- 从服务器拉取完整代码
- 按框架规范整理项目结构
- 配置 Drone CI 测试环境部署
- 包含后端(FastAPI)、前端(Vue3)、管理端

技术栈: Vue3 + TypeScript + FastAPI + MySQL
2026-01-24 19:33:28 +08:00

9.3 KiB
Raw Permalink Blame History

知识点DELETE语句未能删除全部记录的原因分析

问题SQL

DELETE FROM knowledge_points WHERE material_id = 34;

问题描述用户反馈该SQL语句未能删除资料34的全部知识点


🔍 问题分析

1. 数据现状

资料34当前有6个知识点记录

ID 知识点名称 is_deleted 创建时间
1142 FAB法则介绍 0 2025-10-17 07:20:28
1143 全面有效的抗衰需求满足 0 2025-10-17 07:20:28
1144 能量聚焦与精准技术 0 2025-10-17 07:20:28
1145 多层次治疗与专利炮头 0 2025-10-17 07:20:28
1146 国内首款医美合规超声刀的安全性与合规性 0 2025-10-17 07:20:28
1147 提升舒适度与减少副作用 0 2025-10-17 07:20:28

2. 表结构分析

CREATE TABLE `knowledge_points` (
  `id` int NOT NULL AUTO_INCREMENT,
  `course_id` int DEFAULT NULL COMMENT '所属课程ID',
  `material_id` int NOT NULL COMMENT '关联资料ID必填',
  `name` varchar(200) NOT NULL COMMENT '知识点名称',
  `description` text COMMENT '知识点描述',
  `is_deleted` tinyint(1) DEFAULT '0' COMMENT '是否删除',  -- ⚠️ 软删除字段
  `deleted_at` datetime DEFAULT NULL COMMENT '删除时间',
  `created_by` int DEFAULT NULL,
  `updated_by` int DEFAULT NULL,
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
  `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `type` varchar(50) DEFAULT '理论知识',
  `source` tinyint(1) DEFAULT '0',
  `topic_relation` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_course_id` (`course_id`),
  KEY `idx_is_deleted` (`is_deleted`),
  KEY `material_id` (`material_id`),
  CONSTRAINT `knowledge_points_ibfk_1` FOREIGN KEY (`course_id`) 
    REFERENCES `courses` (`id`) ON DELETE CASCADE,
  CONSTRAINT `knowledge_points_ibfk_2` FOREIGN KEY (`material_id`) 
    REFERENCES `course_materials` (`id`) ON DELETE CASCADE
);

关键发现

  • 表中有 is_deleted 字段 → 系统使用软删除机制
  • material_id有外键约束ON DELETE CASCADE
  • course_id有外键约束ON DELETE CASCADE

3. 外键约束检查

-- exam_mistakes表引用knowledge_points
CONSTRAINT exam_mistakes_ibfk_4 
  FOREIGN KEY (knowledge_point_id) 
  REFERENCES knowledge_points(id) 
  ON DELETE SET NULL

检查结果

  • 没有错题记录引用资料34的知识点
  • DELETE_RULE是SET NULL不会阻止删除

问题根因

核心问题系统使用软删除但SQL使用了物理删除

系统设计

  • 后端代码使用 soft_delete() 方法,将 is_deleted 设置为1
  • 前端查询时使用 WHERE is_deleted = 0 筛选未删除的记录
  • 所有删除操作都是软删除,不会真正从数据库删除记录

用户执行的SQL

DELETE FROM knowledge_points WHERE material_id = 34;  -- ❌ 物理删除

为什么"未能删除全部知识点"

有以下几种可能原因:

原因1SQL实际上执行成功了最可能

  • DELETE语句执行成功记录被物理删除
  • 但之后系统又重新创建了这些知识点
  • 🔍 需要检查是否有后台任务或自动同步机制

原因2未提交事务

-- 如果在事务中执行但未提交
START TRANSACTION;
DELETE FROM knowledge_points WHERE material_id = 34;
-- 未执行 COMMIT

原因3没有执行权限

  • 用户可能没有DELETE权限
  • 需要检查用户权限

原因4有触发器或其他机制

  • 可能有BEFORE DELETE或AFTER DELETE触发器阻止删除
  • 需要检查触发器

正确的删除方法

方法1使用系统的软删除推荐

后端API方式

# 通过后端API删除软删除
curl -X DELETE "https://aiedu.ireborn.com.cn/api/v1/courses/materials/34/knowledge-points/{knowledge_point_id}" \
  -H "Authorization: Bearer {token}"

直接SQL方式软删除

-- 软删除资料34的所有知识点
UPDATE knowledge_points 
SET is_deleted = 1, 
    deleted_at = NOW()
WHERE material_id = 34 
  AND is_deleted = 0;

方法2删除资料级联删除知识点

-- 软删除资料,知识点会通过外键级联删除
UPDATE course_materials 
SET is_deleted = 1, 
    deleted_at = NOW()
WHERE id = 34 
  AND is_deleted = 0;

方法3物理删除谨慎使用

⚠️ 警告:物理删除会永久删除数据,无法恢复!

-- 如果确实需要物理删除
DELETE FROM knowledge_points WHERE material_id = 34;

-- 验证删除结果
SELECT COUNT(*) FROM knowledge_points WHERE material_id = 34;
-- 应该返回 0

🔍 排查步骤

1. 检查记录是否真的还在

-- 查看记录数量
SELECT COUNT(*) as total_count 
FROM knowledge_points 
WHERE material_id = 34;

-- 查看详细记录
SELECT id, name, is_deleted, deleted_at 
FROM knowledge_points 
WHERE material_id = 34 
ORDER BY id;

2. 检查事务状态

-- 查看当前未提交的事务
SELECT * FROM information_schema.INNODB_TRX;

-- 如果有未提交的事务,提交或回滚
COMMIT;
-- 或
ROLLBACK;

3. 检查触发器

-- 查看knowledge_points表的触发器
SHOW TRIGGERS LIKE 'knowledge_points';

4. 检查删除权限

-- 查看当前用户权限
SHOW GRANTS FOR 'root'@'%';

-- 或查看当前会话权限
SHOW GRANTS FOR CURRENT_USER;

5. 验证外键约束

-- 禁用外键检查(谨慎使用)
SET FOREIGN_KEY_CHECKS = 0;

-- 执行删除
DELETE FROM knowledge_points WHERE material_id = 34;

-- 重新启用外键检查
SET FOREIGN_KEY_CHECKS = 1;

-- 验证结果
SELECT COUNT(*) FROM knowledge_points WHERE material_id = 34;

📝 推荐操作流程

场景A想要"隐藏"知识点(软删除) 推荐

-- 1. 软删除知识点
UPDATE knowledge_points 
SET is_deleted = 1, 
    deleted_at = NOW(),
    updated_by = {user_id}  -- 记录操作人
WHERE material_id = 34 
  AND is_deleted = 0;

-- 2. 验证结果
SELECT COUNT(*) as deleted_count 
FROM knowledge_points 
WHERE material_id = 34 
  AND is_deleted = 1;

-- 3. 前端查询时会自动过滤
-- SELECT * FROM knowledge_points WHERE material_id = 34 AND is_deleted = 0;
-- 返回 0 条记录

场景B需要永久删除记录物理删除⚠️ 谨慎

-- 1. 备份数据(重要!)
CREATE TABLE knowledge_points_backup_20251017 AS
SELECT * FROM knowledge_points WHERE material_id = 34;

-- 2. 检查依赖关系
SELECT COUNT(*) as dependent_count
FROM exam_mistakes 
WHERE knowledge_point_id IN (
    SELECT id FROM knowledge_points WHERE material_id = 34
);

-- 3. 执行物理删除
DELETE FROM knowledge_points WHERE material_id = 34;

-- 4. 验证结果
SELECT COUNT(*) FROM knowledge_points WHERE material_id = 34;
-- 应该返回 0

-- 5. 提交事务
COMMIT;

🎯 解决方案总结

如果要删除资料34的全部知识点

推荐通过后端API删除资料

# 这会软删除资料及其所有知识点
curl -X DELETE "https://aiedu.ireborn.com.cn/api/v1/courses/{course_id}/materials/34" \
  -H "Authorization: Bearer {token}"

次选SQL软删除

-- 软删除所有知识点
UPDATE knowledge_points 
SET is_deleted = 1, deleted_at = NOW()
WHERE material_id = 34 AND is_deleted = 0;

⚠️ 不推荐SQL物理删除

-- 永久删除(不可恢复)
DELETE FROM knowledge_points WHERE material_id = 34;
COMMIT;  -- 记得提交事务!

🔧 故障排除

如果DELETE语句执行后记录仍然存在

  1. 检查事务是否提交

    COMMIT;
    
  2. 检查是否在错误的数据库

    SELECT DATABASE();
    -- 应该返回 kaopeilian
    
  3. 检查WHERE条件是否正确

    SELECT COUNT(*) FROM knowledge_points WHERE material_id = 34;
    -- 执行DELETE前应该有记录
    
  4. 查看MySQL错误日志

    docker exec kaopeilian-mysql-dev tail -100 /var/log/mysql/error.log
    
  5. 测试简单的DELETE

    -- 删除单条记录测试
    DELETE FROM knowledge_points WHERE id = 1142 LIMIT 1;
    SELECT * FROM knowledge_points WHERE id = 1142;
    

📚 相关文档

  • 数据库架构:/root/aiedu/kaopeilian-backend/数据库架构-统一版.md
  • Service层代码/root/aiedu/kaopeilian-backend/app/services/course_service.py
  • Base Service/root/aiedu/kaopeilian-backend/app/services/base_service.py

💡 经验教训

  1. 理解系统的删除机制

    • 软删除系统中直接使用DELETE可能导致数据不一致
    • 应该使用系统提供的API或软删除SQL
  2. 谨慎使用物理删除

    • 物理删除是不可逆的
    • 删除前应该备份数据
    • 检查是否有外键依赖
  3. 使用事务

    • 重要的删除操作应该在事务中进行
    • 先验证后提交
  4. 记录操作日志

    • 删除操作应该记录操作人和操作时间
    • 便于追溯和审计

结论用户的DELETE语句从语法上是正确的能够执行。如果执行后记录仍然存在最可能的原因是

  1. 事务未提交
  2. 后台任务重新创建了记录
  3. 在错误的数据库环境执行

建议使用软删除而不是物理删除,以保持系统一致性。