传入参数
MyBatis 允许两种方式的使用:通过定义接口,或通过 SqlSession
调用命名空间。这两者的传参方式不同,前者经过 MyBatis 处理后变为后者。后者更直接,当需要传入多个参数时要自己构建 Map
。
当使用接口时,会执行以下步骤:
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.<E>selectList(command.getName(), param);
Object convertArgsToSqlCommandParam (Object[] args)
有以下规则:
- 传入 null 或空数组,返回 null;
- 没有使用
@Param
注解,且数组里只有一个对象,返回该对象; - 否则返回
Map<String, Object>
。
第三种情况下,Map<String, Object>
的数据首先根据 params
从 args
里取。params
是一个 Map<Integer, String>
,存储了形参的顺序和名字,名字的规则是:
- 有
@Param
注解,使用注解的 value - 否则,使用形参顺序
例如:
List<Entity> select(@Param("group") String groupName, Long offset, Integer limits);
对应的 params
(使用 json 格式以便观察):
{
"0": "group",
"1": "1",
"2": "2",
}
注意到只要不带 @Param
注解,就需要使用下标了。
这还没有结束,为了方便允许使用下标,MyBatis 还按 params
顺序设置了另一组值,使得输出的结果类似于:
{
"group": "xxx",
"1": 0,
"2": 20,
"param0": "xxx",
"param1": 0,
"param2": 20,
}
当然了,如果你手动指定的参数名恰好为 param<Index>
以至于跟这条规则重复了,那么 MyBatis 会跳过已经存在的键。
不管是 selectOne
还是 selectMap
方法,都是通过 selectList
执行查询的,不管是 insert
还是 delete
方法,都是通过 update
方法执行的。
在 selectList
和 update
中,对所有参数的都进行了统一的处理。
对于集合,默认使用 DefaultSqlSession::wrapCollection
处理:
private Object wrapCollection(final Object object) {
if (object instanceof Collection) {
StrictMap<Object> map = new StrictMap<Object>();
map.put("collection", object);
if (object instanceof List) {
map.put("list", object);
}
return map;
} else if (object != null && object.getClass().isArray()) {
StrictMap<Object> map = new StrictMap<Object>();
map.put("array", object);
return map;
}
return object;
}
使用参数
- 标准处理(如
#{value}
、#{object.value}
) - 使用 OGNL 方式获取值(如
${orderby}
) - 使用在条件语句中(如
<if test="object.value != null">
)
这里我们注意到可以使用复杂类型,于是我们可以写出非常灵活的动态 SQL,比如:
<update id="update">
UPDATE `Sample`
<set>
<if test="set.name != null">
`name`=#{set.name},
</if>
<if test="set.value != null">
`value`=#{set.value},
</if>
</set>
<trim prefix=" WHERE " prefixOverrides="AND">
<if test="where.id != null">
AND `id`=#{where.id}
</if>
<if test="where.name != null">
AND `name`=#{where.name}
</if>
</trim>
;
</update>