爱思考的程序员
最近在开始思考MyBatis中的一些细节,遇到不会的就找博客,发现这部分内容有所欠缺。
虽然在这条路上我还是个新手,但每次遇到问题最常帮助我的都是这些陌生人的博客,
这次就由我来吧。欢迎转载,请标明出处。有名字就更好了
他俩能干什么
#{}
与${}
的使用
#{}
是占位符填充,如下当我们执行sql语句时会将sql语句中的 #{id}
替换成 ?号
UserDao.java 接口文件:User queryUserByUsername(@Param("username") String username);
UserDaoMapper.xml 映射文件:
<select id="queryUserByUsername" resultMap="user_resultMap">select id,username,password,gender,regist_timefrom t_userwhere username=#{username}</select>
执行后的sql语句:
select id,username,password,gender,regist_timefrom t_userwhere username=?
${}是字符串拼接,多数情况下使用与#{}没区别,但是有下面几点要注意:
注意点
如果这个列是字符类型,我们要加引号,如where username=' u s e r n a m e ′ 如果传入参数是简单类型像是数字、字符串等要在 U s e r D a o . j a v a 中加 @ P a r a m ( " u s e r n a m e " ) 否则 {username}' 如果传入参数是简单类型像是数字、字符串等要在UserDao.java中加@Param("username")否则 username′如果传入参数是简单类型像是数字、字符串等要在UserDao.java中加@Param("username")否则{}取值会有问题
如果是一个引用类型的实例对象参数,那我们可以不加,如:
User queryUserByUsername(@Param (“username”) User user);
存在问题
sql注入风险
使用${}当拼接sql片段时,有sql注入风险,外界参数会改变原有sql的语义,如:
//sql注入String username = "zhangsan' or '1'='1";
注入后的sql语句:
select id,username,password,gender,regist_timefrom t_userwhere username='zhangsan' or '1'='1'
这就导致了哪怕你数据库中没有这个用户名也能成功查询到数据。而使用 #{ } 它会将sql语义过滤,将 zhangsan’ or ‘1’='1 当成一个普通字符串,可以规避sql注入的风险。所以原则上能不用sql拼接就不用sql拼接,那为什么还要有 ${ } 的存在呢?是因为在有些场景中 #{ } 不能使用,如我们要给查询到的数据进行排序
String rule="desc";String sql="select * from t_user order by id ?";
当我们在占位符上填充desc时,会导致sql语句语法出错,这就涉及了占位符的使用原则
//原则:填充数据,要和列相关select * from t_user where id=?inseret into t_user values(?,?,?)update t_user set username?,password=?
显然desc与列无关,就会导致报错
小技巧
MyBatisTest.java 测试方法@Testpublic void test(){UserDao mapper = MyBatisUtil.getMapper(UserDao.class);Integer sig=0; //0:desc 1:ascif(sig==0){mapper.queryUserUsers("desc");}else{mapper.queryUserUsers("asc"); } }
使用 ${}
拼接sql片段的时候,用户传的内容只是一个依据,我们可以通过这个依据进行判断,这时我们就能拼接自己定义的内容,而不是用户输入的内容。这样即使我们拼接了语句也不会被注入,所以这是一个使用 ${ }
时非常重要的小技巧
优势与劣势
优势 劣势
${ }
字符串拼接 可以随意拼接 有sql注入的风险
{ }
占位符 | 规避sql注入风险|要和列相关的位置才可以使用
总结
当我们想要去取值时,能用 #{ }
就尽量用 #{ }
,什么时候不能用 #{ }
呢?如果这个位置不是为某个列做值的相关,而是要在某些sql片段上进行动态填充,那我们必须用 ${ }
来取值。