多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

SQL开发常见问题与错误总结(含报错代码+报错信息完整版)

SQL开发常见问题与错误总结(含报错代码+报错信息完整版) 一、SQL语法层面常见错误最基础、最常犯1. 关键字拼写错误错误场景误写form、wher、selet、gruop by等。报错代码1064报错信息You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near xxx at line x问题本质SQL语法解析失败数据库无法识别错误的关键字。解决方案仔细检查SQL语句确保所有关键字拼写正确。使用IDE的SQL语法高亮和自动补全功能可以有效避免此类错误。2. 标点符号错误错误场景使用中文逗号、中文括号、引号不配对、语句末尾多余分号在某些上下文中。报错代码1064报错信息语法异常、SQL解析终止直接提示syntax error。问题本质SQL解析器遇到无法识别的符号。解决方案确保所有标点符号为英文半角。检查括号、引号是否成对出现。在存储过程或复杂语句中注意分号的使用规则。3. 字段名、表名写错错误场景大小写不符取决于数据库配置、单词拼写错误、名称包含空格未用反引号包裹。报错代码1146:Table xxx doesnt exist1054:Unknown column xxx in field list解决方案使用DESC table_name;或SHOW CREATE TABLE table_name;查看表结构。对于包含空格或特殊字符的标识符使用反引号包裹。注意数据库的lower_case_table_names配置统一大小写风格。4. 别名使用错误错误场景在WHERE、GROUP BY或HAVING子句中直接使用SELECT中定义的列别名。-- 错误示例SELECTuser_idASuid,user_nameFROMusersWHEREuid1;报错代码1054报错信息Unknown column uid in where clause问题本质SQL执行顺序中WHERE子句在SELECT之前执行此时别名尚未生效。解决方案在WHERE子句中使用原始列名或派生表的子查询。5. select * 滥用错误场景无节制地使用SELECT *查询所有字段。报错代码无显性报错无问题本质隐性性能问题。查询冗余传输不必要的数据增加网络I/O。数据加载缓慢特别是包含TEXT、BLOB大字段时。内存占用高应用程序需要处理更多数据。影响索引覆盖无法利用覆盖索引Covering Index优化。解决方案始终指定需要的具体列名。二、聚合函数与分组报错面试高频坑1. group by 与查询字段不匹配错误场景SELECT列表中包含了非聚合字段且未在GROUP BY子句中列出。报错代码1055报错信息Expression #x of SELECT list is not in GROUP BY clause and contains nonaggregated column db.table.column解决方案将SELECT中的所有非聚合列都添加到GROUP BY子句中。使用聚合函数如MAX,MIN,ANY_VALUE处理非分组列。调整sql_mode不推荐仅用于兼容旧系统。2. where筛选聚合函数结果错误场景在WHERE子句中使用COUNT、SUM、AVG等聚合函数进行条件过滤。-- 错误示例SELECTdepartment_id,COUNT(*)FROMemployeesWHERECOUNT(*)5GROUPBYdepartment_id;报错代码1111报错信息Invalid use of group function问题本质WHERE子句在数据分组前执行无法使用聚合函数。解决方案将聚合条件移至HAVING子句。-- 正确示例SELECTdepartment_id,COUNT(*)FROMemployeesGROUPBYdepartment_idHAVINGCOUNT(*)5;3. count统计null值误区错误场景误以为COUNT(column_name)会统计所有行。报错代码无显性报错无问题本质逻辑错误导致统计数据偏少。COUNT(column_name)统计该列非NULL值的行数。COUNT(*)统计表中的总行数包括所有NULL行。COUNT(1)与COUNT(*)效果相同统计总行数。解决方案根据业务需求选择合适的COUNT用法。4. avg计算受null影响错误场景计算平均值时NULL值不参与计算导致分母变小平均值偏大。-- 示例scores 列为 (100, 80, NULL)SELECTAVG(scores)FROMstudent;-- 结果为 (10080)/2 90而非 (10080NULL)/3报错代码无显性报错无问题本质业务数据失真。解决方案使用IFNULL或COALESCE函数将NULL转换为0。SELECTAVG(IFNULL(scores,0))FROMstudent;三、数据库约束相关问题1. MySQL版本check约束差异MySQL 5.7及以下解析但不强制CHECK约束可插入非法数据无报错。MySQL 8.0.16支持并强制CHECK约束。报错代码3819报错信息Check constraint constraint_name is violated.2. 主键重复报错错误场景插入或更新数据时违反了主键的唯一性约束。报错代码1062报错信息Duplicate entry xxx for key PRIMARY解决方案插入前先查询是否存在。使用INSERT ... ON DUPLICATE KEY UPDATE。使用REPLACE INTO注意会先删除再插入。业务上确保主键生成逻辑的唯一性。3. 非空约束报错错误场景向定义了NOT NULL的列插入或更新为NULL值。报错代码1048报错信息Column xxx cannot be null解决方案插入/更新前检查数据确保非空字段有值或设置合理的默认值。4. 唯一约束冲突错误场景违反了唯一索引UNIQUE KEY约束。报错代码1062报错信息Duplicate entry xxx for key key_name解决方案同主键冲突需保证数据唯一性或使用ON DUPLICATE KEY UPDATE。5. 外键约束报错错误场景向子表插入数据引用的主表ID不存在。更新子表的外键值为不存在的主表ID。删除主表中被子表引用的数据。报错代码1452报错信息Cannot add or update a child row: a foreign key constraint fails解决方案插入/更新子表前确保外键值在主表中存在。删除主表数据前先处理子表中的关联数据删除或置空。设置外键的ON DELETE CASCADE或ON UPDATE CASCADE规则需谨慎。四、事务与数据一致性问题转账核心坑1. 忘记关闭自动提交错误场景未设置setAutoCommit(false)每条SQL单独提交。报错代码无显性报错无问题本质事务失效无法实现原子性回滚。解决方案JDBCConnectionconndataSource.getConnection();try{conn.setAutoCommit(false);// 1. 关闭自动提交// ... 执行多条SQL ...conn.commit();// 2. 提交事务}catch(SQLExceptione){conn.rollback();// 3. 异常时回滚}finally{conn.setAutoCommit(true);// 4. 恢复自动提交conn.close();}2. 异常捕获不全导致不回滚错误场景仅捕获SQLException但代码中可能发生NullPointerException、ArithmeticException等运行时异常。结果非SQL异常导致回滚代码未执行部分SQL生效数据不一致。解决方案捕获更广泛的异常如Exception或在finally块中根据状态判断回滚。try{conn.setAutoCommit(false);// ... 业务逻辑 ...conn.commit();}catch(Exceptione){// 捕获所有异常conn.rollback();throwe;}3. 事务未手动commit错误场景开启了事务但未执行commit()。结果所有修改仅存在于当前会话的事务缓冲区其他会话不可见数据看似未更新。解决方案确保事务块的最后执行commit()。4. 锁等待与死锁问题错误场景多个事务互相持有并等待对方释放锁资源。报错代码1213报错信息Deadlock found when trying to get lock; try restarting transaction解决方案重试机制捕获死锁异常后稍作延迟重试事务。访问顺序约定对多个资源的访问顺序如按ID升序。减少事务粒度尽快提交事务缩短锁持有时间。使用乐观锁通过版本号控制。五、查询逻辑错误能运行但结果错误1. 左模糊查询导致索引失效错误场景使用LIKE %keyword或LIKE %keyword%进行查询。结果索引失效全表扫描大数据量时性能极差。解决方案尽量避免左模糊%在开头。使用右模糊LIKE keyword%索引可能生效。考虑全文索引FULLTEXT INDEX或搜索引擎如Elasticsearch。2. NULL值判断语法错误错误场景使用 NULL或! NULL进行判断。-- 错误示例SELECT*FROMusersWHEREemailNULL;-- 永远返回空结果集结果查询结果为空逻辑错误。解决方案必须使用IS NULL或IS NOT NULL。-- 正确示例SELECT*FROMusersWHEREemailISNULL;3. 时间格式不匹配错误场景程序传入的字符串时间格式与数据库字段格式或预期不符。报错代码1292报错信息Incorrect datetime value: xxx解决方案使用参数化查询PreparedStatement传入java.util.Date或java.time对象。确保字符串格式与数据库datetime/timestamp格式匹配如YYYY-MM-DD HH:MM:SS。在SQL中使用STR_TO_DATE()函数明确转换。4. 多表连接逻辑混淆错误场景错误使用INNER JOIN、LEFT JOIN、RIGHT JOIN。INNER JOIN仅返回两个表匹配的行。LEFT JOIN返回左表所有行即使右表无匹配右表字段为NULL。RIGHT JOIN返回右表所有行即使左表无匹配。解决方案明确业务需求选择正确的连接类型。画维恩图辅助理解。5. 多表查询产生笛卡尔积错误场景多表关联时忘记写连接条件。-- 错误示例产生笛卡尔积SELECT*FROMusers,orders;结果数据量爆炸行数 表A行数 × 表B行数可能导致程序崩溃。解决方案始终确保关联查询包含有效的ON或WHERE连接条件。六、数据库性能问题慢查询常见1. 数据表无索引场景对大表进行频繁的查询、更新、删除操作条件字段未建立索引。结果全表扫描性能随数据量增长线性下降。解决方案为WHERE、JOIN、ORDER BY、GROUP BY子句中的常用字段创建索引。使用复合索引时注意最左前缀原则。使用EXPLAIN分析查询执行计划。2. 索引失效多种场景即使创建了索引以下写法也可能导致索引失效LIKE左通配LIKE %valueOR条件WHERE a1 OR b2如果a、b都有索引有时会失效字段运算WHERE YEAR(create_time) 2023应对create_time使用范围查询隐式类型转换WHERE string_column 123索引字段发生类型转换使用NOT、!、某些情况下优化器会放弃使用索引。解决方案编写索引友好的SQL避免在索引列上做计算或函数处理。3. 查询冗余数据场景SELECT *、不合理的LIMIT、查询不需要的列。结果网络传输数据量大应用层内存占用高响应慢。解决方案只查询需要的列。合理使用LIMIT分页避免LIMIT 1000000, 10这种深分页考虑使用游标或条件分页。使用COUNT(1)代替COUNT(*)如果不需要具体列值。4. 循环嵌套查询数据库N1查询问题场景在Java循环中执行单条SQL查询。// 错误示例ListUserusersuserDao.getAllUsers();for(Useruser:users){ListOrderordersorderDao.getOrdersByUserId(user.getId());// 循环中查询数据库user.setOrders(orders);}结果查询次数 1获取用户 N获取每个用户的订单数据库压力大。解决方案使用联合查询JOIN一次获取所有数据。使用批量查询WHERE user_id IN (?)。使用MyBatis等ORM框架的关联查询collection。七、JDBC代码层面SQL问题1. 字符串拼接SQL存在注入风险错误示例StringsqlSELECT * FROM users WHERE username username AND password password;Statementstmtconn.createStatement();ResultSetrsstmt.executeQuery(sql);风险攻击者输入username OR 11即可绕过验证。解决方案永远使用PreparedStatement。StringsqlSELECT * FROM users WHERE username ? AND password ?;PreparedStatementpstmtconn.prepareStatement(sql);pstmt.setString(1,username);pstmt.setString(2,password);ResultSetrspstmt.executeQuery();2. 数据库资源未关闭错误场景未在finally块或 try-with-resources 中关闭Connection、Statement、ResultSet。结果数据库连接耗尽最终导致java.sql.SQLException: Connection is not available。解决方案使用try-with-resourcesJava 7自动关闭资源。try(ConnectionconndataSource.getConnection();PreparedStatementpstmtconn.prepareStatement(sql);ResultSetrspstmt.executeQuery()){// 处理结果集}catch(SQLExceptione){// 异常处理}3. 频繁创建销毁数据库连接场景未使用连接池每次操作都新建Connection。结果创建连接开销大TCP三次握手、认证等并发性能差。解决方案使用数据库连接池如HikariCP、Druid
返回列表