2哥 :3妹,今天怎么下班这么晚啊。
3妹:嗨,别提了,今天线上出bug了, 排查了好久。
2哥:啊,什么问题呀?
3妹:我们内部的一个管理系统报错了, 最近排查下来是mybatis报的错。 背景是这样的:
背景
这个系统的功能比较简单,就是从DB查询用户,并列表展示,用了1年了,都没什么问题。mybatis查询sql是这样的:
<select id="query" resultMap="BaseResultMap">
select id, name, age from user_info where
<if test="name !=null and name !='' ">
name = #{name}
</if>
<if test="age !=null >
AND age = #{age}
</if>
</select>
2哥:这个sql看着也没问题啊
3妹:是的, 本来这个name不会这空的, 所以这个sql一直没问题, 可是最近业务逻辑变了,name可能为空。如果name为空的话就导致这条sql是 where and age=**, 这样就报错了。。
2哥:哦 明白,那3妹觉得有什么优化的方案吗?
3妹:把age查询放在前面吗?那这样age为空就也报错了,那怎么办呢?
2哥:其实,这种问题有2种解决方案,但本质思想是一样的:
方案一:在where最前面增加 1=1
比如改成:
<select id="query" resultMap="BaseResultMap">
select id, name, age from user_info where 1=1
<if test="name !=null and name !='' ">
AND name = #{name}
</if>
<if test="age !=null >
AND age = #{age}
</if>
</select>
这样where后面不会紧跟and, 就不会报错啦。
方案二:表中增加字段deleted
表中增加字段deleted, 一是删除可以软删除, 二是在where最前面加上deleted=0, 这样比加1=1更优雅,也更意义。
<select id="query" resultMap="BaseResultMap">
select id, name, age from user_info where deleted=0
<if test="name !=null and name !='' ">
AND name = #{name}
</if>
<if test="age !=null >
AND age = #{age}
</if>
</select>
扩展:增加1=1, 对性能有影响吗?
网上有种说法是,增加1=1后, 就不走索引,影响查询性能。那我们来测试下吧:
name字段为索引字段,
sql1:
EXPLAIN SELECT * FROM user_info WHERE name='张三';
sql2:
EXPLAIN SELECT * FROM user_info WHERE 1=1 AND name='张三';
通过对比上面两种sql输出结果可以看到possible_keys 和 key都使用到了索引进行检索。
结论:where 1=1 也会走索引,不影响查询效率。
3妹: 我还是在表里增加deleted吧,这样更优雅一些,还可以软删除,一举两得~