问题
项目中有这么一个查询:
SELECT
p.PROJECT_NO AS idNo
FROM
project_execute e
LEFT JOIN project p ON e.project_id = p.ID_NO
WHERE
p.PROJECT_NO LIKE CONCAT( '%', '_22', '%')
是想要对project表的PROJECT_NO字段进行一个模糊匹配,查询出含有_22
的数据,但是查询结果确可以查询出任何包含22
这个字符的数据,_
下划线没有起到作用
问题原因
这是因为在MySQL的LIKE语句中,下划线_是一个通配符,可以匹配任意单个字符。
所以当查询LIKE '%_22%'
时会匹配到包含任意单个字符+22+任意单个字符的字符串。
解决方案
如果项目和我一样使用的是MybatisPlus框架,可以新增一个config重写ConfigurationCustomizer接口中的customize()方法,重写了 setNonNullParameter 方法,对查询参数中的下划线 _ 进行转义处理,将其替换为 \_,以避免被解析为通配符。然后调用父类的 setNonNullParameter 方法将转义后的参数设置到 PreparedStatement 中。具体如下:
@Configuration
public class MyBatisPlusConfig implements ConfigurationCustomizer {
@Override
public void customize(MybatisConfiguration configuration) {
configuration.getTypeHandlerRegistry().register(String.class, new StringTypeHandler() {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
if (parameter.contains("_")) {
parameter = parameter.replace("_", "\\_");
}
super.setNonNullParameter(ps, i, parameter, jdbcType);
}
});
}
}
此时观察日志,打印的sql为:
SELECT
p.PROJECT_NO AS idNo
FROM
project_execute e
LEFT JOIN project p ON e.project_id = p.ID_NO
WHERE
p.PROJECT_NO LIKE CONCAT( '%', '/_22', '%')