mybatis参数处理

为大家简单介绍一下在mybatis中的参数问题:

单个参数:mybatis不会做特殊处理

    #{参数名}:取出参数值

多个参数:mybatis会做特殊处理

        多个参数会被封装成一个map
            key:param1...paramN或者参数的索引也可以
            value:传入的参数的值
        #{}就是从map中获取指定的key的值

   异常:

 org.apache.ibatis.binding.BindingException:
     Parameter 'id' not found.
     Available parameters are [0, 1, param1, param2]

   操作:

        方法:public Dept getByIdAndDname(Integer deptno,String dname);
        取值:#{deptno},#{dname}

    命名参数:明确指定封装参数是map的key:@Param("deptno")Integer deptno

 public Dept getByIdAndDname(@Param("deptno")Integer deptno,@Param("dname")String dname);
        多个参数会被封装成一个map
            key:使用@Param注释指定的值
            value: 参数值
            #{指定的key}取出对应的参数值

POJO:
如果多个参数正好是我们业务逻辑的数据模型,我们就可以直接传入pojo;
    #{属性名}:取出传入的pojo的属性值

Map:
A.如果多个参数不是我们业务逻辑的数据模型,没有对应的pojo,不经常使用,为了方便,我们也可以传入map;
    #{key}:取出map中对应的值
    列子:
        1.接口类:

 public Dept getByMap(Map<String, Object> map);

     2.实现接口类的xml:

        <!--  public Dept getByMap(Map<String, Object> map); -->
            <select id="getByMap" resultType="com.jadeon.mybatis.bean.Dept"
                databaseId="oracle">
                select * from dept where deptno = #{deptno} and dname=#{dname}
            </select>

    3.测试类:

 Map<String, Object> map = new HashMap<>();
                map.put("deptno", 10);
                map.put("dname", "ACCOUNTING");
                Dept dept = deptMapper.getByMap(map);

TO:                
如果多个参数不是我们业务逻辑的数据模型,要经常使用,推荐来编写一个TO(Transfer Object)数据传输对象;
    Page{
        int index;
        int size;
    }

=======================思考=================================
public Dept getDept(@Param("deptno")Integer deptno,String dname);
    取值:deptno==>>#{deptno/param1} dname==>>#{param2}
    
public Dept getDept(Integer deptno,@Param("d")Dept dept);
    取值:deptno==>>#{param1} dname==>>#{param2.dname/d.dname}    

#####特别注意:如果是Collection(List,Set)类型或者是数组,
            也会做特殊处理, 也是把传入的list或者数组封装在map中。
                key:Collection(collection),
                如果是List还可以使用这个key(list)
                数组(array)
public Dept getDeptById(List<Integer> ids);
    取值:取出第一个值:#{list[0]}
    


=======================结合源码,mybatis怎么处理参数=================================
总结:参数多时会封装map,为了不混乱,我们可以使用注解@Param来指定封装时使用的key

 使用#{key}就可以取出map中的值
(@Param("deptno")Integer deptno,@Param("dname")String dname);

ParamNameResolver类解析参数封装map的:
//1、names:{0=deptno,1=dname}:构造器的时候就已经确定
    确定流程:

    1.获取每个标了param注解的参数的@Param的值:deptno,dname;赋值给name;
    2.每次解析一个参数给map中保存信息:(key:参数索引,value:name的值)
        name的值:标注了param注解,注解的值
        没有标注:
            1.全局配置:useActualParamName(jdk1.8);name=参数名
            2.name=map.size();相当于当前元素的索引
            {0=deptno,1=dname,2=2,...}

args[1,"Tom","hellp"]            

public Object getNamedParams(Object[] args) {
        int paramCount = this.names.size();
        //1、参数为null直接返回
        if ((args == null) || (paramCount == 0))
            return null;            
        //2、如果只有一个元素,并且没有Param注解;args[0]
        if ((!(this.hasParamAnnotation)) && (paramCount == 1)) {
            return args[((Integer) this.names.firstKey()).intValue()];
        }        
        //3、多个元素或者Param有标注
        Map param = new MapperMethod.ParamMap();
        int i = 0;
        //4.遍历names集合:{0=deptno,1=dname,2=2}
        for (Map.Entry entry : this.names.entrySet()) {
            //names集合的value作为key;names几个又作为取值的参考args[1,"Tom"]    
            //eg:{deptno=args[0]:10,dname:args[1]: ACCOUNTING,2=args[2}
            
            param.put(entry.getValue(), args[((Integer) entry.getKey()).intValue()]);

            //add generic param names(param1,param2,...)param
            //额外的讲每一个参数也保存到map中,使用新的key:param1,param2,...paramN
            //效果:有Param注解可以#{指定的key},或者(有没有注解都)#{param1}
            String genericParamName = "param" + String.valueOf(i + 1);

            if (!(this.names.containsValue(genericParamName))) {
                param.put(genericParamName, args[((Integer) entry.getKey()).intValue()]);
            }
            ++i;
        }
        return param;
    }

=======================mybatis参数值得获取=================================

#{}:可以获取map中的值或者pojo对象属性的值
${}:可以获取map中的值或者pojo对象属性的值

sql映射文件:select * from dept where deptno = ${deptno} and dname=#{dname}
Preparing: select * from dept where deptno=10 and dname=?
    区别:

        #{}:是以预编译的形式,将参数设置到SQL语句中,PrepareStatement,放在SQL注入;
        ${}:取出的值直接封装到SQL语句中,会有安全问题;
        大多数情况,我们取出参数的值都使用#{};

        原生JDBC不支持占位符的地方我们就可以使用${}进行取值
            比如分表:
                按照年份分表拆分
                    SELECT * FROM ${year}_salary WHERE xxx;
                排序:
                    select * from dept where order by ${deptno} ${desc/asc}
            
#{}:更丰富的用法
    规定参数的一些规则:
        javaType、jdbcType、mode(存储过程)、numbericScale、
        resultMap、typeHandle、jdbcTypeName
        
        jdbcType通常需要在某种特定的条件下被设置:
            在我们数据null的时候,有些数据库可能不识别mybatis对null    的默认处理,比如Oracle报错;
            
            JdbcType OTHER:无效的类型,因为mybatis对所有的null都映射的是原生Jdbc的OTHER类型,Oracle不能正确处理;
            列子:
                错误:
                insert into dept(dname,loc) values (#{dname},#{loc});
                正确:
                insert into dept(dname,loc) values (#{dname},#{loc,JdbcType=NULL});
            由于全局配置文件中:jdbcTypeForNull=OTHER,Oracle不支持
            解决办法:

            1.#{loc,JdbcType=NULL}
            2.jdbcTypeForNull=NULL
            <setting name="jdbcTypeForNull" value="NULL"/>
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值