
无论是在公司的“祖传代码”里,还是在某些自动生成的 SQL 中,你可能都曾见过这样一条“奇怪”的查询:
SELECT * FROM users WHERE 1=1 AND name = 'Alice' AND age > 25;
刚看到时,你可能会满脑子问号:WHERE 1=1?这不永远是真的吗?它有什么意义?是哪个“糊涂”的程序员留下的“废话”吗?
恰恰相反。在某个时代,WHERE 1=1 曾是一个极其聪明的技巧,它巧妙地解决了动态 SQL 拼接中的一个“世纪难题”。本文将带你穿越回那个“JSP/PHP 裸写 SQL”的年代,彻底搞懂 WHERE 1=1 的为什么,并回答那个最重要的问题:在 2025 年的今天,你还应该用它吗?
1. “痛苦”的过去:WHERE 1=1 到底解决了什么问题?
这个技巧的诞生,完全是为了服务于一个特定的场景:动态构建多条件查询 SQL。
想象一下,你正在用 Java(或其他后端语言)构建一个“用户搜索”功能,界面上有三个可选的搜索框:name, city, status。
传统(痛苦)的 SQL 拼接逻辑:
// 假设 name="Alice", city=null, status=1
String name = "Alice";
String city = null;
Integer status = 1;
String sql = "SELECT * FROM users ";
boolean hasWhereClause = false;
if (name != null && !name.isEmpty()) {
sql += "WHERE name = '" + name + "'"; // 第一个条件,要加 WHERE
hasWhereClause = true;
}
if (city != null && !city.isEmpty()) {
if (hasWhereClause) {
sql += " AND city = '" + city + "'"; // 不是第一个,加 AND
} else {
sql += "WHERE city = '" + city + "'"; // 是第一个,加 WHERE
hasWhereClause = true;
}
}
if (status != null) {
if (hasWhereClause) {
sql += " AND status = " + status; // 不是第一个,加 AND
} else {
sql += "WHERE status = " + status; // 是第一个,加 WHERE
hasWhereClause = true;
}
}
// ...
看,这是多么“丑陋”的代码!
为了正确地拼接 WHERE 和 AND,你被迫引入了一个 hasWhereClause 标志位,并且在每一个 if 语句块中都要进行判断。代码冗余、脆弱、且极难维护。如果搜索条件增加到 10 个,这段代码将彻底“腐烂”。
2. “聪明”的技巧:WHERE 1=1 登场
现在,让我们看看“老前辈”们想出的“天才”技巧。
使用 WHERE 1=1 拼接的逻辑:
// 假设 name="Alice", city=null, status=1
String name = "Alice";
String city = null;
Integer status = 1;
// 1. 构造一个永远为真的 "恒等式"
String sql = "SELECT * FROM users WHERE 1=1";
// 2. 后续所有条件,都可以无脑追加 "AND"
if (name != null && !name.isEmpty()) {
sql += " AND name = '" + name + "'";
}
if (city != null && !city.isEmpty()) {
sql += " AND city = '" + city + "'";
}
if (status != null) {
sql += " AND status = "To_String(status)" + status;
}
// 最终生成的 SQL:
// SELECT * FROM users WHERE 1=1 AND name = 'Alice' AND status = 1
看! 通过在 WHERE 子句中预置一个永远为真的 1=1,WHERE 关键字被“占用”了。我们后续所有的动态条件,都可以统一、无脑地以 AND 开头进行拼接,再也不需要那个该死的 hasWhereClause 标志位了!
WHERE 1=1 在这里就像一个“占位符”,它充当了动态查询条件的“地基”,极大地简化了 SQL 字符串拼接的逻辑。
3. 性能拷问:WHERE 1=1 会拖慢查询吗?
这是初学者最关心的问题:增加一个 1=1 的判断,是不是会让数据库多做一次“无用功”?
答案是:在现代数据库中,完全不会。
WHERE 1=1 是一个**“恒真式”。MySQL、PostgreSQL、SQL Server 等主流数据库的查询优化器 (Query Optimizer)**,在SQL解析阶段就足够“聪明”地识别出 1=1 是一个无意义的、永远为真的条件。
它会直接将 1=1 这一项从查询树中“剪枝”优化掉,根本不会带入到最终的执行计划中。
执行计划(EXPLAIN)对比流程图:
结论: EXPLAIN SELECT ... WHERE name = 'Alice' 和 EXPLAIN SELECT ... WHERE 1=1 AND name = 'Alice',你会发现它们的执行计划是完全一致的。WHERE 1=1 对性能的影响为 零。
4. 2025 年的“灵魂拷问”:现在还建议这么写吗?
答案:不建议,甚至应该被“禁止”。
WHERE 1=1 作为一个“技巧”,它所处的时代,是手动拼接 SQL 字符串的时代。而“手动拼接 SQL”这个行为本身,就是万恶之源。
A. 最大的“原罪”:SQL 注入 (SQL Injection)
观察我们上面的“聪明”技巧:
sql += " AND name = '" + name + "'";
如果一个黑客在 name 输入框里填的不是 Alice,而是 ' OR 1=1 -- 呢?
sql 语句就变成了:
SELECT * FROM users WHERE 1=1 AND name = '' OR 1=1 --' AND status = 1
-- 是 SQL 注释符,它会注释掉后面的所有内容。最终执行的 SQL 变成了:
SELECT * FROM users WHERE 1=1 AND name = '' OR 1=1
这个查询会绕过所有条件,返回 users 表中的所有数据。这就是最经典的 SQL 注入攻击。
B. 现代的“王道”:参数化查询与 ORM 框架
在 2025 年的今天,我们几乎不应该再手动拼接 SQL 了。我们拥有了更安全、更强大的工具:
1. MyBatis (动态 SQL 标签):
MyBatis 的 XML 映射完美地解决了 WHERE 和 AND 的拼接问题。
<select id="findUsers" resultType="User">
SELECT * FROM users
<where>
<if test="name != null and name != ''">
AND name = #{name}
</if>
<if test="city != null and city != ''">
AND city = #{city}
</if>
<if test="status != null">
AND status = #{status}
</if>
</where>
</select>
MyBatis 会智能地加上 WHERE 关键字,并自动去掉第一个 if 成立时的 AND。
2. JPA (Criteria API / Specification):
JPA 更是通过“规约 (Specification)”或“查询构建器 (CriteriaBuilder)”在 Java 代码中以类型安全的方式构建查询,完全告别了 SQL 字符串。
// Spring Data JPA 示例
Specification<User> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (name != null) {
predicates.add(cb.equal(root.get("name"), name));
}
if (city != null) {
predicates.add(cb.equal(root.get("city"), city));
}
return cb.and(predicates.toArray(new Predicate[0]));
};
userRepository.findAll(spec);
JPA 会在底层为我们生成最优化、最安全的 SQL,我们根本不需要关心 WHERE 1=1。
5. 总结
| 对比维度 | WHERE 1=1 技巧 | 现代 ORM / 框架 (MyBatis/JPA) |
|---|---|---|
| 诞生背景 | 手动 SQL 字符串拼接时代 | 自动化、类型安全的时代 |
| 核心目的 | 简化 AND 的拼接逻辑 | 屏蔽 SQL,关注业务对象 |
| 性能影响 | 零 (会被优化器移除) | (不适用) |
| 安全风险 | 极高 (通常伴随 SQL 注入风险) | 极低 (天生支持参数化查询) |
| 现代建议 | 不推荐,应被废弃 | 强烈推荐,行业标准 |
WHERE 1=1 是一个时代的眼泪,它是一个聪明的“HACK”,但也是一个过时的“HACK”。
在今天的开发中,如果你在代码里看到了 WHERE 1=1,你不应该赞叹它的“巧妙”,而应该立刻拉响警报:这段代码很可能在裸奔(SQL注入),并且没有使用现代的持久化框架!
WHERE 1=1 还值得用吗?
6004

被折叠的 条评论
为什么被折叠?



