乐趣区

关于java:MyBatis中占位符可能导致查询结果为空的问题

问题起源

刚学习 springboot 不久,在测试 DAO 层时,发现怎么测试都返回的空集,然而间接在 sql console 中可能正确返回后果。源代码如下:

DAO 层

@Select("select * from tb_book where ${condition} like" +
        "concat('%',#{conditionKey},'%') limit #{pageStart}," +
        "#{pageSize}")
ArrayList<Book> getByCondition(int pageStart, int pageSize, String condition, String conditionKey);

DAO 测试类

@Test
void testGetByCondition(){
    String conditionKey = "java" ;
    System.out.println(bookMapper.getByCondition(0, 4, "name", conditionKey));
}

失常状况下,通过 console 可能输入两条后果,然而测试时却是空集,却没有报错,到底咋回事。在网上怎么找都找不到相干相似的问题,最初在 stackoverflow 上找到一个靠谱的答案,把我指引向 mybatis 官网文档。认真钻研之后发现,其实问题就出在最最根底的字符串占位符上,也就是 #{}${}的问题。

#{}并不是能够无脑替换所有的数据~~~~

文档中是这么写的:

By default, using the #{} syntax will cause MyBatis to generate PreparedStatement properties and set the values safely against the PreparedStatement parameters (e.g. ?). While this is safer, faster and almost always preferred, sometimes you just want to directly inject an unmodified string into the SQL Statement. For example, for ORDER BY, you might use something like this: ORDER BY ${columnName}. Here MyBatis won’t modify or escape the string.

也就是说在运行时,咱们代码中的 where #{condition} 被放进了预编译的后果中,导致在解析时,被认为是 where "name" ... , 这样显然不对,然而程序没有报错,sql 日志也没有任何线索,所以这个问题能够说是十分难发现了。

解决方案

晓得是占位符的问题之后,解决起来比较简单了,就是不必#{}, 改用${}。尽管可能会有 sql 注入的问题,然而这里也是无奈之举,最好的方法还是不要偷懒,分成两个或者多个 sql 语句来写会比拟好。如果有什么更好的计划,欢送探讨~~

退出移动版