在mybatis
中,占位符有两个,一个是#,一个是$,这两个有什么区别,我们分别来讲解一下
1. 占位符#{}
语法:#{字符}
#占位符告诉mybatis
使用实际的参数值代替。并,#{…}代替sql
语句的"?"。这样做更安全,更迅速,通常也是首选做法
mapper文件中
<select id="selectStudentById" parameterType="int" resultType="com.lu.entity.Student">
select id, name, email, age from student where id = #{studentId}
</select>
转为mybatis
的执行是:
String sql = "select id, name, email, age from student where id = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, 1001); //传递参数
ResultSet rs = ps.executeQuery(); //执行sql语句
#{}占位符的特点:
- 使用
PrepareStatement
对象执行sql
语句 - 使用
PrepareStatement
对象,能避免sql
注入,sql
语句执行更安全 - #{}常常作为列值使用的,位于等号的右侧,#{}位置的值和数据类型有关的
2. 占位符${}
语法:${字符}
mybatis
执行${}占位符的sql
语句
<select id="selectStudentById" parameterType="int" resultType="com.lu.entity.Student">
select id, name, email, age from student where id = ${studentId}
</select>
表 示 字 符 串 连 接 , 把 ‘ s q l ‘ 语 句 的 其 他 内 容 和 {}表示字符串连接,把`sql`语句的其他内容和 表示字符串连接,把‘sql‘语句的其他内容和{}内容使用字符串(+) 连接的方式连在一起
转为mybatis
的执行是:
String sql = "select id, name, email, age from student where id =" + "1001";
Statement stmt = conn.createStatement(sql);
ResultSet rs = stmt.executeQuery();
${}的特点
- 使用Statement对象,执行
sql
语句,效率低 - ${}占位符的值,使用的字符串连接方式,有
sql
注入的风险。有代码安全的问题 - ${}数据是原样使用的,不会区分数据类型
- 常 用 作 表 名 或 者 列 明 , 再 能 保 证 数 据 安 全 的 情 况 下 使 用 {}常用作表名或者列明,再能保证数据安全的情况下使用 常用作表名或者列明,再能保证数据安全的情况下使用{}
我们来实现一个例子,首先在dao
接口中写方法
List<Student> queryStudent(@Param("studentname") String name);
在mapper文件中
<select id="queryStudent" resultType="com.lu.entity.Student">
select * from student where name = ${studentname}
</select>
在测试类中
@Test
public void testQueryStudent() {
SqlSession session = MyBatisUtil.getSqlSession();
StudentDao dao = session.getMapper(StudentDao.class);
List<Student> students = dao.queryStudent("张三");
students.forEach(student -> System.out.println(student));
session.close();
}
我们来执行一下
报了一个错,代码把张三当成一个列了,那么我们怎么修改呢
List<Student> students = dao.queryStudent("'张三'");
我们需要在传值的时候在值的两边加上单引号 ''
再重新执行一下,发现可以查询成功了
还有一点我们需要注意的,就是在dao
接口中定义方法的时候,我们必须用@Param
来指定名称,不然同样会报错。
${}最不能解决的问题,就是sql
注入的问题,关于sql
注入,可以看这一篇文章
3. #{}和${}组合使用
有时候我们单独的使用#{}或者${}都不能很好的解决问题,比如下面这个例子
我们要从指定的数据中查询名字为XXX的数据,并且按照姓名进行降序排序
首先在dao
接口中定义方法
List<Student> queryStudentOrderByColumn(@Param("myname") String name, @Param("colName") String colName, @Param("tableName") String tableName);
在mapper文件中
<select id="queryStudentOrderByColumn" resultType="com.lu.entity.Student">
select * from ${tableName} where name = #{myname} order by ${colName} desc
</select>
在测试类中
@Test
public void testQueryStudentOrderByColName() {
SqlSession session = MyBatisUtil.getSqlSession();
StudentDao dao = session.getMapper(StudentDao.class);
List<Student> students = dao.queryStudentOrderByColumn("张三", "id", "student");
students.forEach(student -> System.out.println(student));
session.close();
}
控制台输出:
现在我们已经实现了#{}和${}的组合使用