Mybatis返回数据条数正确但具体数据为null

省流:因为select出来的字段没取别名

一个平静的下午,朋友让我帮他看个问题,前端获取数据列表显示查询成功,但是所有数据都是null
错误信息

解决过程:

首先考虑通过整个数据的传输链条,跟着数据传播路径逐步缩小范围

  • 第一步在后端controller打断点,查看前端传入的参数和后端此处的返回是否正常
    此处查看发现前端传的查询参数正常,后端返回结果也为null,因此判定问题出在后端内部
  • 走个过场查一下service层,与controller一样;(我好像没见service单独出过错)因此判断是与数据库交互的部分出现了问题
  • mapper.xml中对应的语句放入MySQL执行,发现没问题,因此问题应该出在Mybatis的部分
  • 仔细考虑Mybatis的运行过程,从命名空间到语句id,再到结果封装与映射
  • 最后在封装返回结果集处发现问题

大火可以看看自己能不能看出来,很简单的问题,但是也值得深入去了解

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.test.mapper.TestProvinceMapper">

    <resultMap id="testProvinceResultMap" type="com.ruoyi.test.domain.TestProvince" autoMapping="true" />
    <resultMap id="testProvinceVoResultMap" type="com.ruoyi.test.domain.TestProvinceVo" />

    <select id="list" resultMap="testProvinceVoResultMap">

        select
        tp.province_name,tc.country_name 
        from
        test_province tp
        left join
        test_country tc
        on
        tp.country_id = tc.county_id
        <where>
            <if test="provinceName != null and provinceName != ''">
                and province_name = #{provinceName}
            </if>
        </where>

    </select>

</mapper>

以下为本人手写的Mybatis简单实现对应部分,以此为基础讲一下错误的根源(懒得找Mybatis自己的)

//        6、封装返回结果集
        while(resultSet.next()){
            Object o = resultTypeClass.newInstance();
            ResultSetMetaData metaData = resultSet.getMetaData();
            for(int i=1;i<=metaData.getColumnCount();i++){
                //                字段名字
                String columnName = metaData.getColumnName(i);
                //                字段的值
                Object value = resultSet.getObject(columnName);
                //                使用反射,根据数据库表和实体的对应关系,完成封装
                // 根据列名和结果集对象类型构造PropertyDescriptor 
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClass);
                //获取写入属性的方法,此处的getWriteMethod是根据刚刚传入的columnName进行的
                Method writeMethod = propertyDescriptor.getWriteMethod();
                //执行写入方法,向o对象中写入value值
                writeMethod.invoke(o,value);
            }
            objects.add(o);
        }

Mybatis封装结果集时设置属性值的执行流程

首先是会根据传入字段的名字构造一个PropertyDescriptor对象

随后根据getWriteMethod()获取写入对应属性的方法,注意,此处底层是根据刚刚传入的columnName进行获取write方法的,具体代码如下:

//第一步使用的构造方法
public PropertyDescriptor(String propertyName, Class<?> beanClass)
                throws IntrospectionException {
        this(propertyName, beanClass,
                Introspector.IS_PREFIX + NameGenerator.capitalize(propertyName),
                Introspector.SET_PREFIX + NameGenerator.capitalize(propertyName));//capitalize会转化为大驼峰
                //此处为获取枚举常量值,其实就是'set',然后加上变量名,这也是为什么我们平时一贯要求'set'方法如此命名的原因
    }
//上述构造方法调用的另一个构造方法    
public PropertyDescriptor(String propertyName, Class<?> beanClass,
                String readMethodName, String writeMethodName)
                throws IntrospectionException {
        ·······
        setName(propertyName);
        setClass0(beanClass);

        this.readMethodName = readMethodName;
        ·······
        this.writeMethodName = writeMethodName;
        ·······
    }
//capitalize
public static String capitalize(String name) {
        if (name == null || name.length() == 0) {
            return name;
        }
        return name.substring(0, 1).toUpperCase(ENGLISH) + name.substring(1);
    }

可以看出,传入的 columnName通过内部处理转化为了propertyName,并且经过转化和拼接构造了writeMethodName,也就是会根据传入的 columnName跟set拼接成为为方法名,以同事的错误为例,tp.province_name字段select出来之后列名会是province_name,也就是说最后生成的方法名会是setProvince_name,那么在利用反射寻找方法的时候就会找不到对应的set方法,以至于无法赋值,所以导致最后获取到的元素个数正确但均为null的问题

只能说太久没手写确实很容易犯这种错误,写到这应该算是解释清楚了

但是我又产生新的疑问了,为什么根据错误的方法名去找方法执行,居然不会报错???

等有时间仔细查看一下这中间的执行过程吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值