Mybatis实战 之 参数取值方式
在Mybatis 的 Mapper接口文件时,我们可以使用两种方式来获取参数值即#{} 和 ${},下面我们将通过里来说明一下两者的区别。
实例
首先我们编写一条语句,然后分别使用#{} 和 ${} 分别取值。
sql
select * from products where pid=${pid,jdbcType=INTEGER} and type=#{type,jdbcType=VARCHAR}
编译后的语句
Preparing: select * from products where pid=25 and type=?
由上面的SQL 语句可以看出 ${} 和 #{} 都可以取出参数中的值但有以下区别:
使用#{} 时,SQL入参使用的时预编译的方式,同时使用的是PreparedStatement,可以防止SQL注入
使用${}时,SQL直接将参数值拼接在SQL中,因而不安全。
使用场景
既然两种方式都可以取值,那么一定可以得出的结论就是:各有各的优缺点。#{} 的取值方式
大多数场景中我们都应该使用#{}的取值方式来取值。${}的取值方式
原生jdbc不支持占位符的地方我们就可以使用 进行取值,比如分表、排序等时,可以使用 {}
来取值。比如今年时2017年,我们查询的表时products-2017表,若是2018则理应查询的时products-2018。那么此时我们便可以使用${}在取值。分表查询
select * from products-${year} where pid=#{pid,jdbcType=INTEGER}
排序查询
<!--order 时传过来的排序条件--> select * from products order by ${order}
扩展
#{} 更丰富的用法
在使用#{} 的取值方式时 #{}在设置参数规则上还有更多用法。比如javaType、 jdbcType、 mode(存储过程)、 numericScale、resultMap、 typeHandler、 jdbcTypeName、 expression等。例子
Mybatis 封装JDBCTYPE类型的源码* Copyright 2009-2015 the original author or authors. package org.apache.ibatis.type; import java.sql.Types; import java.util.HashMap; import java.util.Map; /** * @author Clinton Begin */ public enum JdbcType { /* * This is added to enable basic support for the * ARRAY data type - but a custom type handler is still required */ ARRAY(Types.ARRAY), BIT(Types.BIT), TINYINT(Types.TINYINT), SMALLINT(Types.SMALLINT), INTEGER(Types.INTEGER), BIGINT(Types.BIGINT), FLOAT(Types.FLOAT), REAL(Types.REAL), DOUBLE(Types.DOUBLE), NUMERIC(Types.NUMERIC), DECIMAL(Types.DECIMAL), CHAR(Types.CHAR), VARCHAR(Types.VARCHAR), LONGVARCHAR(Types.LONGVARCHAR), DATE(Types.DATE), TIME(Types.TIME), TIMESTAMP(Types.TIMESTAMP), BINARY(Types.BINARY), VARBINARY(Types.VARBINARY), LONGVARBINARY(Types.LONGVARBINARY), NULL(Types.NULL), OTHER(Types.OTHER), BLOB(Types.BLOB), CLOB(Types.CLOB), BOOLEAN(Types.BOOLEAN), CURSOR(-10), // Oracle UNDEFINED(Integer.MIN_VALUE + 1000), NVARCHAR(Types.NVARCHAR), // JDK6 NCHAR(Types.NCHAR), // JDK6 NCLOB(Types.NCLOB), // JDK6 STRUCT(Types.STRUCT), JAVA_OBJECT(Types.JAVA_OBJECT), DISTINCT(Types.DISTINCT), REF(Types.REF), DATALINK(Types.DATALINK), ROWID(Types.ROWID), // JDK6 LONGNVARCHAR(Types.LONGNVARCHAR), // JDK6 SQLXML(Types.SQLXML), // JDK6 DATETIMEOFFSET(-155); // SQL Server 2008 public final int TYPE_CODE; private static Map<Integer,JdbcType> codeLookup = new HashMap<Integer,JdbcType>(); static { for (JdbcType type : JdbcType.values()) { codeLookup.put(type.TYPE_CODE, type); } } JdbcType(int code) { this.TYPE_CODE = code; } public static JdbcType forCode(int code) { return codeLookup.get(code); } }
在使用Mysql作为DB时,如果穿过来的参数为null,那么Mybatis 会将null 解析并定义为jdbcType=OTHER,同时Mysql 数据库支持OTHER并将其视为null。
但使用Oracle作为DB时,如果传过来的参数为null时,mybatis也会将null解析并定义为jdbcType=OTHER,但Oracle并不支持jdbcType=OTHER这个数据类型。
解决办法
在Mybatis的配置文件中的settings中做一下设置:<setting name="jdbcTypeForNull" value="NULL"/>
统一将参数值为空的参数的jdbcType统一设置成为为 jdbcType=NULL,这样Mysql和Oracle都将支持该种jdbcType。