I. Introduction
Use Mybatis biggest feature is the sql need to write, and write sql inevitably need to pass multiple parameters. I believe we have encountered in the use of Mybatis the "Parameter 'array' not found. Available parameters are [xsids, param1]" an error like this, we will summarize the way Mybatis complex parameter passing parameters to take the Senate.
Second, do not use @Param comment
[A] transmitting List <xx> Type Parameters: When not in use @Param annotations, in xml by foreach loop must now specify the collection = "list" or collection = "collection" to remove the parameters;
(. 1) Mapper. .java:
/**
* mybatis传复杂参数(不使用@Param("xxx")指定参数名称)
*/
List<Map<String, Object>> getStudentsByListNoParamName(List<Integer> pkids);
(2). Mapper.xml:
<!--
List<Map<String, Object>> getStudentsByListNoParamName(List<Integer> pkids);
注意: 因为没有通过@Param指定参数名称,mybatis规定如果是Collection并且没有指定参数名称,那么collection="list"必须为list或collection
否则报错:Parameter 'xxx' not found. Available parameters are [collection, list]
-->
<select id="getStudentsByListNoParamName" resultType="map" parameterType="list">
select * from tbl_student t
where 1 = 1
and t.s_id in
<foreach collection="collection" open="(" close=")" separator="," index="index" item="pkid">
#{pkid}
</foreach>
</select>
or:
<!--
List<Map<String, Object>> getStudentsByListNoParamName(List<Integer> pkids);
注意: 因为没有通过@Param指定参数名称,mybatis规定如果是Collection并且没有指定参数名称,那么collection="list"必须为list或collection
否则报错:Parameter 'xxx' not found. Available parameters are [collection, list]
-->
<select id="getStudentsByListNoParamName" resultType="map" parameterType="list">
select * from tbl_student t
where 1 = 1
and t.s_id in
<foreach collection="list" open="(" close=")" separator="," index="index" item="pkid">
#{pkid}
</foreach>
</select>
(3) unit test code:
@Test
public void testNoParams() {
List<Integer> pkids = new ArrayList<>();
pkids.add(1);
pkids.add(2);
List<Map<String, Object>> students1 = studentMapper.getStudentsByListNoParamName(pkids);
for (Map<String, Object> map : students1) {
System.out.println(map);
}
}
. (4) The result:
If the wrong xml as the following, it will error:
<select id="getStudentsByListNoParamName" resultType="map" parameterType="list">
select * from tbl_student t
where 1 = 1
and t.s_id in
<foreach collection="xsids" open="(" close=")" separator="," index="index" item="pkid">
#{pkid}
</foreach>
</select>
[B] transmitting Array array type parameters: When not in use @Param annotations, in xml by foreach loop must now specify the collection = "array" to remove parameter;
(. 1) Mapper.java:.
List<Map<String, Object>> getStudentsByArrayNoParamName(Integer[] pkids);
(2). Mapper.xml:
<!--
List<Map<String, Object>> getStudentsByArrayNoParamName(Integer[] pkids);
注意: 因为没有通过@Param指定参数名称,mybatis规定如果是Array数组类型并且没有指定参数名称,那么collection="array"必须为array
否则报错:假如我们指定collection="array1",那么报错如下: Parameter 'array1' not found. Available parameters are [array]
-->
<select id="getStudentsByArrayNoParamName" resultType="map">
select * from tbl_student t
where 1 = 1
and t.s_id in
<foreach collection="array" open="(" close=")" separator="," index="index" item="pkid">
#{pkid}
</foreach>
</select>
(3) unit test code:
@Test
public void testNoParams() {
List<Map<String, Object>> students2 = studentMapper.getStudentsByArrayNoParamName(new Integer[]{1, 2, 3});
for (Map<String, Object> map : students2) {
System.out.println(map);
}
}
. (4) The result:
If the xml file written in the wrong, it will error.
<select id="getStudentsByArrayNoParamName" resultType="map">
select * from tbl_student t
where 1 = 1
and t.s_id in
<foreach collection="array12" open="(" close=")" separator="," index="index" item="pkid">
#{pkid}
</foreach>
</select>
[C] transmitting Map Type Parameters: When not in use @Param annotations, the xml file by key} # {map the extracted parameters;
(. 1) Mapper.java.:
List<Map<String, Object>> getStudentsByMapNoParamName(Map<String, Object> param);
(2). Mapper.xml:
<!--
List<Map<String, Object>> getStudentsByMapNoParamName(Map<String, Object> param);
注意: 因为没有通过@Param指定参数名称,mybatis规定如果是map类型并且没有指定参数名称,那么在xml中取值的时候:
对于普通属性:对应map.put('aaa',bbb) map中的key键
对于集合类型属性:也是对应map.put('aaa',bbb) map中的key键
对于这个示例,如下:
paramMap.put("sname", "zhangsan2"); 取值方式 -> #{sname}
paramMap.put("pkids", pkids2); 取值方式 -> collection="pkids"
-->
<select id="getStudentsByMapNoParamName" parameterType="map" resultType="map">
select * from tbl_student t
where 1 = 1
<if test="sname!=null and sname!=''">
and t.s_name = #{sname}
</if>
<if test="pkids != null and pkids.size() > 0">
and t.s_id in
<foreach collection="pkids" open="(" close=")" separator="," index="index" item="pkid">
#{pkid}
</foreach>
</if>
</select>
(3) unit test code:
@Test
public void testNoParams() {
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("sname", "zhangsan2");
List<Integer> pkids2 = new ArrayList<>();
pkids2.add(1);
pkids2.add(2);
paramMap.put("pkids", pkids2);
List<Map<String, Object>> students3 = studentMapper.getStudentsByMapNoParamName(paramMap);
for (Map<String, Object> map : students3) {
System.out.println(map);
}
}
. (4) The result:
Third, the use @Param comment
[A] transmitting List <xx> Type Parameters: If the specified parameter name xsids, then the mode values: collection = "xsids", at this time the default collection, list fail;
(. 1) .Mapper.java:
/**
* mybatis传复杂参数(使用@Param("xxx")指定参数名称)
*/
List<Map<String, Object>> getStudentsByListWithParamName(@Param("xsids") List<Integer> pkids);
(2) .Mapper.xml:
<!--
List<Map<String, Object>> getStudentsByListWithParamName(@Param("xsids") List<Integer> pkids);
因为我们指定了参数名称为xsids,所以取值方式:collection="xsids", 此时默认的collection、list会失效
如果我们使用collection="list", 会报错:Parameter 'list' not found. Available parameters are [xsids, param1]
-->
<select id="getStudentsByListWithParamName" resultType="map" parameterType="list">
select * from tbl_student t
where 1 = 1
and t.s_id in
<foreach collection="xsids" open="(" close=")" separator="," index="index" item="xsid">
#{xsid}
</foreach>
</select>
(3) unit test code:
@Test
public void testWithParams() {
List<Integer> pkids = new ArrayList<>();
pkids.add(1);
pkids.add(2);
List<Map<String, Object>> students1 = studentMapper.getStudentsByListWithParamName(pkids);
for (Map<String, Object> map : students1) {
System.out.println(map);
}
}
. (4) The result:
If the collection is not xml "xsid", you will get an error
<select id="getStudentsByListWithParamName" resultType="map" parameterType="list">
select * from tbl_student t
where 1 = 1
and t.s_id in
<foreach collection="list" open="(" close=")" separator="," index="index" item="xsid">
#{xsid}
</foreach>
</select>
[B] passed Array type parameters: If we specify the parameter name xsids, then the value of the way: collection = "xsids", this time the default array will fail;
(1) .Mapper.java:
List<Map<String, Object>> getStudentsByArrayWithParamName(@Param("xsids") Integer[] pkids);
(2) .Mapper.xml:
<!--
List<Map<String, Object>> getStudentsByArrayWithParamName(@Param("xsids") Integer[] pkids);
因为我们指定了参数名称为xsids,所以取值方式:collection="xsids",此时默认的array会失效.
如果我们使用collection="array", 会报错:Parameter 'array' not found. Available parameters are [xsids, param1]
-->
<select id="getStudentsByArrayWithParamName" resultType="map">
select * from tbl_student t
where 1 = 1
and t.s_id in
<foreach collection="xsids" open="(" close=")" separator="," index="index" item="pkid">
#{pkid}
</foreach>
</select>
(3) unit test code:
@Test
public void testWithParams() {
List<Map<String, Object>> students2 = studentMapper.getStudentsByArrayWithParamName(new Integer[]{1, 2, 3});
for (Map<String, Object> map : students2) {
System.out.println(map);
}
}
. (4) The result:
If the collection is not @Param xml designated name, the same will complain:
<select id="getStudentsByArrayWithParamName" resultType="map">
select * from tbl_student t
where 1 = 1
and t.s_id in
<foreach collection="xsids123" open="(" close=")" separator="," index="index" item="pkid">
#{pkid}
</foreach>
</select>
[C] pass argument of type Map: If we use @Param ( "paramMap") parameter specifies the name paramMap, then our values in the xml time, you need to paramMap.xxx, xxx is the corresponding map of the key;
(1) .Mapper.java:
List<Map<String, Object>> getStudentsByMapWithParamName(@Param("paramMap") Map<String, Object> param);
(2) .Mapper.xml:
<!--
List<Map<String, Object>> getStudentsByMapWithParamName(@Param("paramMap") Map<String, Object> param);
由于我们使用@Param("paramMap")指定了参数名称为paramMap,所以我们在xml中取值的时候,就需要通过paramMap.xxx,
xxx就是对应map中的键,如下
paramMap.put("sname", "zhangsan2"); 取值方式 -> #{paramMap.sname}
paramMap.put("pkids", pkids2); 取值方式 -> collection="paramMap.pkids"
-->
<select id="getStudentsByMapWithParamName" parameterType="java.util.Map" resultType="map">
select * from tbl_student t
where 1 = 1
<if test="paramMap.sname!=null and paramMap.sname!=''">
and t.s_name = #{paramMap.sname}
</if>
<if test="paramMap.pkids != null and paramMap.pkids.size() > 0">
and t.s_id in
<foreach collection="paramMap.pkids" open="(" close=")" separator="," index="index" item="pkid">
#{pkid}
</foreach>
</if>
</select>
(3) unit test code:
@Test
public void testWithParams() {
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("sname", "zhangsan2");
List<Integer> pkids2 = new ArrayList<>();
pkids2.add(1);
pkids2.add(2);
paramMap.put("pkids", pkids2);
List<Map<String, Object>> students3 = studentMapper.getStudentsByMapWithParamName(paramMap);
for (Map<String, Object> map : students3) {
System.out.println(map);
}
}
. (4) The result:
Note that, when the parameters that need to remove the key with the corresponding values on the Map, or takes no parameters.
Four, mybatis analytical parameters encapsulated source map
-
下面通过查看mybatis源码了解一下里面是怎么封装参数的,同时可以加深我们对传递参数和取出参数的理解。Mybatis中参数解析过程主要是在这个类 -> ParamNameResolver.java: 下面对源码做了一些注释说明,大家也可以debug一步一步查看其中怎么封装参数的。
// 假设args=[2,学生2],names={0=sid,1=sname}
public Object getNamedParams(Object[] args) {
int paramCount = this.names.size();
//参数不为空时,封装成map
if (args != null && paramCount != 0) {
//如果没有@Param注解并且参数个数只有一个,直接返回args[0]
if (!this.hasParamAnnotation && paramCount == 1) {
return args[(Integer)this.names.firstKey()];
} else {
Map<String, Object> param = new ParamMap();
int i = 0;
//遍历names: {0=sid,1=sname}
for(Iterator var5 = this.names.entrySet().iterator(); var5.hasNext(); ++i) {
Entry<Integer, String> entry = (Entry)var5.next();
//names集合的value作为key;
//names集合的key作为取值的参考args[0]
//params: sid=args[0]=2 sname=args[1]=学生2
param.put(entry.getValue(), args[(Integer)entry.getKey()]);
String genericParamName = "param" + String.valueOf(i + 1);
//注意从1开始, param1...paramN
//params: param1=2 param2=学生2
if (!this.names.containsValue(genericParamName)) {
param.put(genericParamName, args[(Integer)entry.getKey()]);
}
}
return param;
}
} else {
//参数为空的时候直接return null
return null;
}
}
V. Summary
- When the method without @param annotation, and when only one parameter:
[A] String types, xml can be can be extracted parameter values # {arbitrary value};
[b] Entity Object Type: xml can be extracted parameter values # {entity object attribute name};
[c] Map type: xml file can be taken out by the key # {map key} parameter;
[d] List type: xml must write collection = "list" or collection = "collection" can be taken out only the parameter values;
[e] array array type: xml must write collection = "array" can be taken out only the parameter values;
- When the method plus @param annotations, and when only one parameter:
String type, etc. [a]: The @param (value = "name") , xml can be used # {name} # {param1} or remove parameters;
[b] Entity Object Type: The @param (value = "student "), xml through # {.} Student object attribute value, or the param1 # object properties {.} extracted parameter values;
[c] type Map: The @param (value =" paramsMap ") , xml through # { paramsMap.map key} the value, or the key} # {param1.map extracted parameter values;
[d] List collection type: as @param (value = "ids") , xml may be by collection = "ids" or collection = "param1" extraction of parameter values;
[e] Array types: as @param (value = "ids") , this time to write collection = "ids" or collection = "param1" extraction of parameter values;
- When a plurality of parameters, if not specified @Param, you can use # {param1}, # {param2} ... # {paramN} or removed using # {0}, # {1} ... # {N} removed otherwise you will not find an abnormal message parameters; if @Param (value = "xxx") specified, take the time parameters may specify names using @Param # {xxx} or removed using # {param1}, # {param2 } ... # {paramN} removed.