调试动态 SQL(Dynamic SQL)通常是开发中比较头疼的问题,因为 SQL 是在运行时拼出来的,不像静态 SQL 那样一眼就能看到。下面从思路、方法、工具、示例几个层面系统讲一下。
第一步永远不是“执行”,而是“看到最终 SQL”
动态 SQL 的问题,90% 都出在:
所以调试的核心就是:
String sql = "SELECT * FROM user WHERE 1=1 ";
if (name != null) {
sql += " AND name = '" + name + "'";
}
if (age != null) {
sql += " AND age = " + age;
}
✅ 打印最终 SQL
System.out.println(sql);
❌ 不要直接执行,先复制到:
✅ 观察:
AND"null"String sql = "SELECT * FROM user WHERE name = ? AND age = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, name);
ps.setInt(2, age);
log.info("SQL: {}, params: {}, {}", sql, name, age);
⚠️ 注意:
? 不能直接替换执行<select id="queryUser">
SELECT * FROM user
<where>
<if test="name != null">
AND name = #{name}
</if>
<if test="age != null">
AND age = #{age}
</if>
</where>
</select>
✅ 开启 MyBatis SQL 日志
logback / log4j
<logger name="com.xxx.mapper" level="DEBUG"/>
或(MyBatis 自带)
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
你会看到:
==> Preparing: SELECT * FROM user WHERE name = ?
==> Parameters: Tom(String)
✅ 还能用:
SET @sql = CONCAT('SELECT * FROM ', table_name);
PREPARE stmt FROM @sql;
EXECUTE stmt;
SELECT @sql;
或
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = @sql;
把动态 SQL 先写成:
SELECT 'DEBUG' AS flag, 'SELECT * FROM user WHERE name=...' AS sql_text;
不要一次拼完,逐步打印:
sql += " AND age = " + age;
System.out.println(sql);
| 问题 | 表现 |
|---|---|
| 引号未闭合 | SQL 语法错误 |
| NULL 拼成字符串 | 查不到数据 |
| 多一个 AND | WHERE AND … |
| 日期格式 | 2024-01-01 vs 2024/1/1 |
| 参数类型 | String vs Number |
| LIKE 漏 % | 匹配不到 |
✅ 能用参数化就用参数化
✅ 能用 ORM 就用 ORM
✅ 动态 SQL 用 <where> / <trim>
✅ 所有 SQL 都有日志开关
✅ 写单测验证 SQL 生成
如果你愿意,可以:
这样最快。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。