记录一次mybatis占位符使用错误的问题:
mapper.xml 的正确使用#{}, 会在查询时拼接' ', 保证=两边的数据类型都是String
<select id="selectByCustNoAndProdNo" resultType="string" parameterType="java.lang.String">
select ORDER_NO from trx_order_info t where t.CUST_NO=#{custNo} and t.prod_sub_no=#{prod_sub_no} limit 1;
</select>
一 : 理解mybatis中 $与#
在mybatis中的$与#都是在sql中动态的传入参数。
参数是动态的,可变的。当你传入什么样的值,就会根据你传入的值执行sql语句。
二 : 使用$与#
#{}
: 解析为一个 JDBC 预编译语句(prepared statement)的参数标记符,一个 #{ } 被解析为一个参数占位符 。拼接sql时会加上' ',适用于字符串类型的参数拼接。
${}
: 仅仅为一个纯碎的替换,在动态 SQL 解析阶段将会进行变量替换。不会额外加' ', 适用于数值类型的参数拼接。
name-->cy
eg: select id,name,age from student where name=#{name} -- > name='cy'
select id,name,age from student where name=${name} --> name=cy
三: mysql的隐式转换
当错误使用占位符时, 比如上面t.CUST_NO为varchar类型, 使用${}占位符拼接到sql中不带'', 而恰巧cust_no是数字值,导致mysql出现=两边数据(字符串=数值)类型不一致,发生隐式转换(数值->字符串),索引失效问题。
MySQL使用操作符的一些特性:
- 当操作符左右两边的数据类型不一致时,会发生隐式转换。
- 当where查询操作符左边为数值类型时发生了隐式转换,那么对效率影响不大,但还是不推荐这么做。
- 当where查询操作符左边为字符类型时发生了隐式转换,那么会导致索引失效,造成全表扫描效率极低。(重要)
- 字符串转换为数值类型时,非数字开头的字符串会转化为0,以数字开头的字符串会截取从第一个字符到第一个非数字内容为止的值为转化结果。
所以,我们在写SQL时一定要养成良好的习惯,查询的字段是什么类型,等号右边的条件就写成对应的类型。特别当查询的字段是字符串时,等号右边的条件一定要用引号引起来标明这是一个字符串,否则会造成索引失效触发全表扫描。