• Mybatis中由于${}直接注入引发的问题


    一、问题引入

    我们先来看这段代码,我想从取值为${category}的表中查询全部信息。

    @Mapper
    public interface CategoryMapper {
        @Select("select * from ${category}")
        List<Commodity> queryAllByCategory(String category);
    }

    刚开始觉得没毛病,但是令人失望的是抛出了下面的异常。

    org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'category' in 'class java.lang.String'

    二、${ }与#{ }的区别

    为了搞清楚背后的原因,首先我们来聊一聊${}与#{}的区别。

    我们通过一个例子来简述两者的区别。

    select * from commodity where id=#{id} AND title='${title}'

    在动态 SQL 解析阶段, #{ } 和 ${ } 会有不同的表现:

    #{ } 解析为一个JDBC 预编译语句的参数标记符占位符 ?。

    上面的例子就被解析为

    select * from commodity where id= ?

    ${ } 仅仅为一个纯碎的 string 替换,在mybatis的动态 SQL 解析阶段将会进行变量替换。比如:传入的参数是“牙膏”,就会将${title}替换成牙膏。

    select * from commodity where id=? AND title='牙膏'

    然后把解析好的语句再通过JDBC执行。

    所以因为在${ } 在预编译之前已经被变量替换了,这会存在 sql 注入问题。比如:传入的studentName参数是“‘1' OR '1'='1’”

    在mybatis中解析完成后变成了

    select * from commodity where id=? AND title='1' OR '1'='1'

    此时不管id为任何值,都可以查出全部内容。

    因此能使用#{ }就尽量不要使用${ } ,因为${ }存在sql注入问题。

    所以通俗来说${ }是直接用变量替换值的,而#{}会将变量转换为字符串再进行替换。

    三、问题解决

    通过理解上面的${ }的传值方式,可以知道${ } 在预编译之前已经被变量替换了,它是被直接注入的,所以会在String中去获取category的getter方法。

    那么我们通过什么方法去解决这个问题呢?此时就要引入@Param。

    @Mapper
    public interface CategoryMapper {
        @Select("select * from ${category}")
        List<Commodity> queryAllByCategory(@Param("category") String category);
    }

    @Param的作用就是给参数命名,参数命名后就能根据名字得到参数值,正确的将参数传入sql语句中

    其实可以理解为@Param将参数包装成一个Map(因为我们知道,如果想要sql语句中有多个参数的时候,可以通过将这些参数封装成一个Map,在通过Map的key来取出参数),即{"category", "xxxx"},然后在${category}中取到xxx。

    然后就能查出结果啦。

    当然,如果采用${value}这种写法,就没这个问题了,不过这个写法仅适用于参数只有一个的情况。

    @Mapper
    public interface CategoryMapper {
        @Select("select * from ${value}")
        List<Commodity> queryAllByCategory(String category);
    }
     
  • 相关阅读:
    java枚举实例
    POI读取excel
    POI导入
    javascript闭包
    dom4j测试
    Android开发UI之ListView中的Button点击设置
    eclipse不自动弹出提示(Alt+/ 快捷键失效)
    Android开发之全局获取Context的技巧
    Android开发之点击两次Back键退出App
    Android开发UI之开源项目第一篇——个性化控件(View)篇
  • 原文地址:https://www.cnblogs.com/z1014601153/p/14148094.html
Copyright © 2020-2023  润新知