Mybatis complex parameters taking reference parameter passing mode summary

Disclaimer: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/Weixiaohuai/article/details/90605569

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.

Guess you like

Origin blog.csdn.net/Weixiaohuai/article/details/90605569