之前做项目时,由于自己对之前学过的,用过的知识都没有去总结,时间一久,就会忘记,而当出现问题时,往往需要很长时间才能找到问题原因,从而浪费了大量时间在定位上,言归正传,现在说说之前遇到的一个问题。
使用mybatis时动态传参,我们都知道使用#{},这也是绝大多数场景用到的,
而有一次,我需要在后台拼接查询参数,放入in中,我拼接的参数格式为‘p001','p002','p003'这样的,in条件的写法in (#{product})
结果就是查询不到数据,但是把sql和参数拿到plsql中却完全没问题,当时脑子短路,一直没想到问题的原因在哪,白白牺牲了将近一下午时间。
后来突然想到$符号,后来将$符号代替#号就OK了。
问题原因:
#{} 默认会用引号将参数引起来
${} 单纯替代。
之前的写法,select * from product_tree_v pv where pv.product_code in(#{product})
预编译出来的结果:select * from product_tree_v pv where pv.product_code in ?;
#{}被当作一个占位符了,而参数前后也会被加上引号。
运行时的sql是:select * from product_tree_v pv where pv.product_code in('‘p001','p002','p003'');
所以无论如何都是查不到数据的。
换成${}:select * from product_tree_v pv where pv.product_code in($product});
预编译出来的结果 :select * from product_tree_v pv where pv.product_code in (‘p001','p002','p003');
这样就是纯粹的将参数传进去,没有做任何的转义操作。这才是我们真正想要的。
总结:
mybatis作为ORM框架,从性能,系统维护性,实用性上来说,都是非常优秀的,
其所有的sql在执行前都会通过数据库驱动进行预编译,这样DBMS就可以不用编译直接接收参数运行,
而#和$号的区别在预编译后就能看出来了,#{}预编译完是占位符?,而${}预编译完就是传进来的参数。
#{}的优点:
使用#{}可以预防sql攻击,而${}却不能
例如 select * from ${tablename} 如果传入的是 product; drop product;
那么你的表数据就会被无声无息的干掉了。
使用${}的场景:
1 作为in条件时,
2 参数为int类型并且数据库中字段的类型是number,
3 表名
4 order by ${},排序字段
--------ps---------
<![CDATA[]]>
的用法,在该符号内的语句,将不会被当成字符串来处理,而是直接当成sql语句,比如有大于,小于号,要执行一个存储过程
都需要加上这个。