Mybatis的#占位符和$占位符的使用方法、区别、适合的使用区域

1 篇文章 0 订阅
1 篇文章 0 订阅

#占位符的特点

1)使用的PrepareStatement对象,执行sql语句,效率高
2)使用的PrepareStatement对象,能避免sql语句,sql语句执行更安全
3)#{}常作为【列值】使用的,一般用来传递列值。【重点】

$占位符的特点

1) 使用$()传参时,在dao接口必须使用@Param命名参数
2)使用Statement对象,执行sql语句,效率低
3)${}占位符的值,使用的是字【符串连接的方式】,有sql注入的风险,有代码安全的问题
4)${}数据是【原样使用的,不会区分数据类型】
5)${}【适合用作表名或列名】,不适合用作 列值 使用,在能保证数据安全的情况下使用${}【重点】

对比:

dao接口方法:

List<Student> queryStudent(@Param("studentName") String name);

mapper内的对应sql语句:

<!--${}的sql语句-->
<select id="queryStudent" resultType="com.gys.domain.Student">
    select * from User where name=${studentName}
</select>

<!--#{}的sql语句-->
<select id="queryStudent" resultType="com.gys.domain.Student">
    select * from User where name=#{studentName}
</select>

测试:

//#{}的执行sql语句方法
@Test
public void testSelectByName(){
    SqlSession session = MyBatisUtil.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);
    List<Student> students = dao.queryStudent("李四");  
    students.forEach(student -> System.out.println("学生: "+student));
    session.close();
}


//${}的执行sql语句方法
@Test
public void testSelectByName(){
    SqlSession session = MyBatisUtil.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);
//这里因为${}是原样使用,字符串拼接,所以 必须传入的是 ”‘李四’“,而不能是 “李四”
    List<Student> students = dao.queryStudent("'李四'");  
    students.forEach(student -> System.out.println("学生: "+student));
    session.close();
}

mybatis根据上述代码自动生成的sql语句:

//#{}自动生成的sql语句
Preparing: String Sql =“select * from User where name= ? ”
Parameters: 李四(String)


//${}自动生成的sql语句
Preparing: String Sql =“select * from User where name= '李四' ”
Parameters:

【重点】

这里#{} 是把 李四 这个 sting类型的值 传递给了 name,

而${} 是把 李四 和 前面的 sql语句 作为字符串拼接在了一起。

上述这种查询写法自然是看不出#{}和${}都用作列值的区别

但!下面举例把 ${} 用作列值的不安全性!

用户使用正常数据输入:李四。 #{}和${}两者返回的数据都没问题。

用户使用错误数据输入:李四 or 1=1 。此时,#{}和${}返回的结果就不想同了。

此时,#{} 是把  (李四 or 1=1) 作为一个整体,把这个整体作为一个值传给了 name,通过匹配数据库User表的name列,查找name = (李四 or 1=1) 的这个学生

但是,${} 是把 李四 or 1=1 拼接在了 sql语句后面,此时 mybatis自动生成的sql语句变成了:

String sql = " select * from User where name='李四' or 1=1 "

整个sql语句的意思就被用户自己改变

本来是查找名字为:李四 or 1=1  的这个学生,最多只会产生一条返回结果;

现在变成了 查找名字为 李四 或者 1  代表真,查询User所有用户,则一定会暴露出数据库User表中的所有数据。

这就体现了${}作为列表的不安全性

${} 适用领域:用作 表名列名

对比 #{} 和 ${} 用作 表名列名

dao接口方法:

//#{}和${}
List<Student> queryStudentOrderByColName(@Param("ColName") String name);

mapper的sql语句:

<!--#{}-->
<select id="queryStudentOrderByColName" resultType="com.gys.domain.Student">
    select * from User order by #{ColName}
</select>

<!--${}-->
<select id="queryStudentOrderByColName" resultType="com.gys.domain.Student">
    select * from User order by ${ColName}
</select>

测试语句:

        #{}测试语句:

//#{}
@Test
    public void testSelectOrderByColName(){
        SqlSession session = MyBatisUtil.getSqlSession();
        StudentDao dao = session.getMapper(StudentDao.class);
        List<Student> students = dao.queryStudentOrderByColName("name");
        students.forEach(student -> System.out.println("学生: "+student));
        session.close();
    }

        mybatis内部解释:

Preparing: String sql = "select * from User order by ?"
Parameters: name(String)

        结果:

转化为 数据库中的语句: select * from User order by 'name'
注意,这是错误的 通过 name列排序,  正确的为 order by name
这是因为 #{} 记录的 name 是String 类型,再进行赋值操作后,传入数据库就是  ‘name’,而不是 name

        ${}测试语句:

//${}
@Test
    public void testSelectOrderByColName(){
        SqlSession session = MyBatisUtil.getSqlSession();
        StudentDao dao = session.getMapper(StudentDao.class);
        List<Student> students = dao.queryStudentOrderByColName("name");
        students.forEach(student -> System.out.println("学生: "+student));
        session.close();
    }

        mybatis内部解释:

Preparing: String sql = " select * from User order by name "
Parameters:

        结果:

转化为 数据库中的语句: select * from User order by name
这才是正确的sql语法
这是因为 ${} 是把 ${} 的数据 拼接 到了 sql语句后面,而不是 赋值。

一般都是#{}和${}混合使用:

dao接口的方法:

List<Student> queryStudentOrderByColName(@Param("tableName") String tableName,
                                             @Param("dataName") String dataName,
                                             @Param("ColName") String ColName);

mapper内的sql语句:

<!--* 处也可以用 ${}代替--> 
<select id="queryStudentOrderByColName" resultType="com.gys.domain.Student">
        select * from ${tableName} where ${dataName} order by ${ColName}
</select>

测试语句:

@Test
    public void testSelectOrderByColName2(){
        SqlSession session = MyBatisUtil.getSqlSession();
        StudentDao dao = session.getMapper(StudentDao.class);
        List<Student> students = dao.queryStudentOrderByColName2("User","李四","name");
        students.forEach(student -> System.out.println("学生: "+student));
        session.close();
    }

mybatis内部解释:

Preparing: select * from User where name=? order by ? 
Parameters: 李四(String), name(String)

结果:

搜索 User表 中 name=李四所有用户,并按照 name 列 排序

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值