参数处理
单个参数
通过#{参数名}
取出参数值
接口定义如下
public User getUserByUserName(String userName);
接口对应的 Mapper.xml 定义如下所示
<select id="getUserByUserName"
parameterType="String"
resultType="com.example.mybatis.entity.User">
select
id, username, user_email userEmail, user_city userCity, age
from user
where username = #{username}
</select>
多个参数
MyBatis会做特殊处理,会将你的多个参数封装成一个Map,key
为param1, param2,..., paramN
,value为 value1,value2,...valueN
,可以通过#{param1}
来获取value1
的值,#{paramN}
来获取valueN
的值。value1,value2,...valueN
就是我们通过方法传递过来的值。
接口定义如下
public User getUserByIdAndUserName(Integer id, String username);
接口对应的 Mapper.xml 定义如下所示。 两个参数分别是 Integer 类型和 String 类型,类型不一致,此时 parameterType 可以省略 。
<select id="getUserByIdAndUserName"
resultType="com.example.mybatis.entity.User">
select
id, username, user_email userEmail, user_city userCity, age
from user
where id = #{param1}
and username = #{param2}
</select>
这里需要注意的是通过 #{param1} 和 #{param2} 来映射两个参数,以此类推,如果有第 3 个参数,则使用 #{param3} 来映射。
命名参数
MyBatis封装参数时由用户来指定Map的key.
接口定义如下
public User getUserByIdAndUserName(@Param("id")Integer id, @Param("username")String username);
接口对应的 Mapper.xml 定义如下所示
<select id="getUserByIdAndUserName"
resultType="com.example.mybatis.entity.User">
select
id, username, user_email userEmail, user_city userCity, age
from user
where id = #{id}
and username = #{username}
</select>
POJO
多个参数一个个写太麻烦了,这时候我们可以将参数列表进行封装,将封装对象作为 parameterType 的值。
接口定义如下
public User getUserByIdAndUserName(User user);
接口对应的 Mapper.xml 定义如下所示
命名参数:封装参数时指定Map的key,
<select id="getUserByIdAndUserName"
parameterType="com.example.mybatis.entity.User"
resultType="com.example.mybatis.entity.User">
select
id, username, user_email userEmail, user_city userCity, age
from user
where id = #{id}
and username = #{username}
</select>
与多个参数的不同之处在于,这里是通过 #{属性名}
来映射参数对象的具体属性值的。
有时候为了方便,也可以直接使用Map来传递数据,但是使用Map会使得代码的可读性很差,一般不推荐使用这种方式。
特殊情况
如果参数类型是Collection(List,Set)类型或者是数组,MyBatis也会特殊处理
如果为Collection类型的,key为collection;如果为List类型的,key为list
public int addUserList(List<User> userList);
接口对应的 Mapper.xml 定义如下所示
<insert id="addUserList"
parameterType="com.example.mybatis.entity.User"
useGeneratedKeys="true"
keyProperty="id">
insert into user
(username, user_email, user_city, age)
values
<foreach item="item" collection="collection" separator=",">
(#{item.username}, #{item.userEmail}, #{item.userCity}, #{item.age})
</foreach>
</insert>
如果是数组类型,key为array
接口定义如下
public int addUserList(User[] userList);
接口对应的 Mapper.xml 定义如下所示
<insert id="addUserList"
parameterType="com.example.mybatis.entity.User"
useGeneratedKeys="true"
keyProperty="id">
insert into user
(username, user_email, user_city, age)
values
<foreach item="item" collection="array" separator=",">
(#{item.username}, #{item.userEmail}, #{item.userCity}, #{item.age})
</foreach>
</insert>
#{}与${}取值区别
#{}
是以预编译的形式将参数设置到sql语句中,防止SQL注入,${}
取出的值直接拼装在SQL语句中,会有安全问题。
不过有时你就是想直接在 SQL 语句中插入一个不转义的字符串。 比如,像 ORDER BY,你可以这样来使用
ORDER BY ${columnName}
这里 MyBatis 不会修改或转义字符串。
当 SQL 语句中的元数据(如表名或列名)是动态生成的时候,字符串替换将会非常有用。 举个例子,如果你想通过任何一列从表中 select
数据时,不需要像下面这样写:
@Select("select * from user where id = #{id}")
User findById(@Param("id") long id);
@Select("select * from user where name = #{name}")
User findByName(@Param("name") String name);
@Select("select * from user where email = #{email}")
User findByEmail(@Param("email") String email);
可以只写这样一个方法:
@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String value);
其中 ${column}
会被直接替换,而 #{value}
会被使用 ?
预处理。因此你就可以像下面这样来达到上述功能:
User userOfId1 = userMapper.findByColumn("id", 1L);
User userOfNameKid = userMapper.findByColumn("name", "kid");
User userOfEmail = userMapper.findByColumn("email", "noone@nowhere.com");
这个方法也同样适用于用来替换表名的情况。
#{}指定 jdbcType
只需要在可能执行插入、更新和删除的且允许空值的列上指定 JDBC 类型。这是 JDBC 的要求而非 MyBatis 的要求。
为了以后可能的使用场景,MyBatis 通过内置的 jdbcType 枚举类型支持下面的 JDBC 类型。
BIT | FLOAT | CHAR | TIMESTAMP | OTHER | UNDEFINED |
---|---|---|---|---|---|
TINYINT | REAL | VARCHAR | BINARY | BLOB | NVARCHAR |
SMALLINT | DOUBLE | LONGVARCHAR | VARBINARY | CLOB | NCHAR |
INTEGER | NUMERIC | DATE | LONGVARBINARY | BOOLEAN | NCLOB |
BIGINT | DECIMAL | TIME | NULL | CURSOR | ARRAY |
在我们数据为null
的时候,有些数据库可能不能识别MyBatis对null
的默认处理。比如Oracle,MyBatis对所有的null
都映射成原生JDBC的OTHER
类型,Oracle不能正确处理,但是MySQL却能处理。