首页
学习
活动
专区
圈层
工具
发布

SQL中为什么不要使用1=1?

在写 SQL 时,很多人喜欢在 WHERE 条件里加上1=1,比如这样:

SELECT * FROM user WHERE 1=1 AND name = 'Tom' AND age > 20;

看起来挺方便对吧?尤其是那种动态拼接 SQL 的代码里,这样写能少写一点判断逻辑。但其实,这种写法有几个隐藏的坑,尤其是在生产环境下,可能带来性能问题、逻辑问题,甚至安全风险。

一、1=1 的由来

很多老项目都是通过字符串拼接来生成 SQL 的,比如 Java 里:

String sql = "SELECT * FROM user WHERE 1=1";

if (name != null) {

  sql += " AND name = '" + name + "'";

}

if (age != null) {

  sql += " AND age = " + age;

}

这样写最大的“优点”就是不用管是不是第一个条件,反正前面加个AND肯定不会出错。但问题在于,这种偷懒的写法虽然方便,却埋下了不少坑。

二、执行层面的问题

数据库在解析 SQL 时,1=1其实是一个恒为真的表达式,它不会影响结果,但它仍然要被数据库解析、优化、执行。

数据库优化器在执行 SQL 时会建立执行计划(execution plan),而1=1这种无意义的条件会让优化器多做一次逻辑判断。虽然这个判断代价很小,但在高并发系统中,如果每秒执行上万条 SQL,这种“无意义的运算”会累计成可观的开销。

比如下面这两条语句:

SELECT * FROM order WHERE 1=1 AND status = 'PAID';

SELECT * FROM order WHERE status = 'PAID';

执行结果完全一样,但第一条会让优化器多一步逻辑判断。在单条 SQL 里可能差别不明显,但如果在循环里拼接执行几千次,就会变成资源浪费。

三、可维护性问题

1=1虽然能让拼接 SQL 的代码简单点,但当 SQL 越来越复杂,比如带上JOIN、EXISTS、GROUP BY时,这种写法会让语句难以阅读、难以维护。

尤其是当你查日志时,看到类似这样的:

SELECT u.id, u.name, o.amount

FROM user u

LEFT JOIN order o ON u.id = o.user_id

WHERE 1=1 AND u.status = 'active' AND o.create_time > '2024-01-01';

1=1完全没有意义,反而会让人觉得这条语句是拼接出来的,从而怀疑有没有 SQL 注入的风险。

四、安全隐患(SQL 注入)

如果项目中没有使用参数化查询,而是直接拼接字符串(这种情况老项目特别多),1=1很容易和 SQL 注入问题扯上关系。

比如下面的例子:

String sql = "SELECT * FROM user WHERE 1=1";

sql += " AND name = '" + inputName + "'";

如果用户输入Tom' OR 1=1 --拼出来的 SQL 变成:

SELECT * FROM user WHERE 1=1 AND name = 'Tom' OR 1=1 --';

这就等于直接查询了整个表。很多人以为用了1=1只是为了拼接方便,但它在 SQL 注入中其实是攻击者最喜欢的“突破口”。

五、动态 SQL 的正确做法

现代项目一般不会直接拼接 SQL,而是通过框架来安全生成,比如 MyBatis、JPA 等。 以 MyBatis 为例,你可以这样写:

SELECT * FROM user

<where>

  <if test="name != null">

    AND name = #{name}

  </if>

  <if test="age != null">

    AND age = #{age}

  </if>

</where>

MyBatis 的标签会自动去掉多余的AND或OR,根本不需要1=1。 最终生成的 SQL 是干净的、安全的,比如:

SELECT * FROM user WHERE name = 'Tom' AND age = 25;

这才是动态 SQL 的正确姿势。

六、如果实在要拼接怎么办?

如果你真的在写 JDBC 原生代码,建议至少使用StringBuilder加上参数绑定(PreparedStatement),避免直接拼接:

StringBuilder sql = new StringBuilder("SELECT * FROM user WHERE 1=1");

List<Object> params = new ArrayList<>();

if (name != null) {

  sql.append(" AND name = ?");

  params.add(name);

}

if (age != null) {

  sql.append(" AND age = ?");

  params.add(age);

}

PreparedStatement ps = connection.prepareStatement(sql.toString());

for (int i = 0; i < params.size(); i++) {

  ps.setObject(i + 1, params.get(i));

}

ResultSet rs = ps.executeQuery();

虽然这里仍然用了1=1,但至少使用了参数绑定,不会被注入攻击利用。 当然,更好的办法是直接判断第一个条件是否需要WHERE,而不是靠1=1来糊弄过去。

七、总结一下

小结

1=1这种写法在 10 年前确实很常见,因为那时候大家还在手写 SQL 拼接,但现在的框架早就帮你解决了动态拼接的问题。

如果还在项目里看到WHERE 1=1,基本可以判断这段代码是旧时代遗留物。 与其靠1=1去规避逻辑,不如老老实实写条件判断,或者交给框架去拼接。

毕竟,干净的 SQL 不只是为了美观,更是性能、安全和可维护性的基础。

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OcoF7mvbwVdCh0424hGsA-Uw0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。
领券