【方向盘】MyBatis封装结果集时,Integer类型的id字段被赋值成了Long类型---读源码找原因(下)

简介: 【方向盘】MyBatis封装结果集时,Integer类型的id字段被赋值成了Long类型---读源码找原因(下)

看看我们关心的id属性:


image.png


oh my god。元数据里面保存的根本就不是我们以为的setId(Integer id)这种,而是保留有父类自己的东西。所以我们自然就好理解了,为什么set进去一个BigInteger值竟然也不抱错的原因了(它也继承了Number类)。


到此,我们就算把出现这种现象的原因完全给弄明白了。


but,but,but。这其实并没有彻底的让我“心服口服”,至少有两大问题一直困扰着我,没有找到根本原因。


疑问提出


(此处暂时只提出两个问题做出解答,更加详细的,可以关注后续我的撸管MyBatis源码专题)


1、为何getValue匹配类型转换器的时候,找到的是UnknownTypeHandler?


(本问题此处大概讲一下,更加详细的,MyBatis的类型转换器模式,完全需要拉一个专题出来讲解)


MyBatis内部注册和维护了几乎所有的类型转换器,所以我们平时使用的时候根本就不用管,它自动就能跟我们匹配上,转换成我们需要的结果。在初始化的时候,有个转换器注册类:TypeHandlerRegistry:(列出部分)


image.png


我们会发现3.4版本的MyBatis对 JSR 310标准的日期时间也提供了支持

顺带我们可以看一下,框架升级给我们带来的优雅体验:


image.png


我们发现3.4.6版本处理起来,就优雅很多,大赞。


UnknownTypeHandler对应的类型:


register(Object.class, UNKNOWN_TYPE_HANDLER);
    register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
    register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);


我们会发现,它对应的都是Object类型。


MyBatis在进行初始化的时候,会把所有的xml文件里的ResultMap进行注册,并且提供全局访问。而当注册到此处的继承情况的时候,在获取xml继承的id类型的时候,因为是继承的,所以拿不到实际类型,从而注册不到对应的处理器,最终只能交给UnknownTypeHandler处理


下面一个简单的例子,大家可以感受一下MyBatis为啥注册时候找不到了:


 public static void main(String[] args) throws NoSuchFieldException {
        //Field id = Son.class.getField("id");
        //System.out.println(id); //若id是从父类继承来的,传入的泛型  java.lang.Number com.sayabc.boot2demo1.api.TestController$BaseEntity.id
        //System.out.println(id); //id是本类自己的属性 public java.lang.Integer com.sayabc.boot2demo1.api.TestController$Son.id
        //另外一种方式(属性都是private的都ok)
        Field id = Son.class.getSuperclass().getDeclaredField("id");
        System.out.println(id); //我们会发现获取的SuperClass的  类型直接是java.lang.Number 根本没得商量
    }
    class Son extends BaseEntity<Integer> {
        //public Integer id;
        private String name;
    }
    //此处为了方便反射 属性用public的
    class BaseEntity<PK extends Number> {
        public PK id;
    }


我们能够得出结论。当属性是从父类继承过来的,反射去获取这个字段的类型,它的类型是父类类型。(本例如果没有继承自Number,那返回的就是Object类型)


2、为何刚看到的元数据metaClass对象保存的是父类的setId方法呢?作何考虑?这个值又是什么时候被赋值放进去的呢?


这几个问题其实相对来说比较简单些,如果熟悉流行开源框架的这方面的设计思想,发现都是通的,大家都这么“玩”。因此这个问题我这里就不做解答了,留给读者自己思考一番吧


MyBatis结果集如果是Map遇上泛型的话,也是可能遇上同样问题的。


说到最后


  框架能极大提高我们的开发效率,甚至我们可以基于开源本身定制出更符合我们业务的框架。


一件事本身的复杂度不会减少,它只是从一个地方转移到了另外一个地方而已,总的复杂度是恒定不变的,这是一个定理。


(比如这次的撸源码调试找问题就非常耗时,从开始到搞明白花了整4个小时左右,耗时的原因关键是MyBatis自己存在我上面指出的软病,加大了定位问题的难度)



相关文章
|
2月前
|
Java 数据库连接 数据库
mybatis查询数据,返回的对象少了一个字段
mybatis查询数据,返回的对象少了一个字段
176 8
|
5天前
|
SQL Java 数据库连接
【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段
MyBatis-Plus是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。本文讲解了最新版MP的使用教程,包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段等核心功能。
【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段
|
25天前
|
SQL Java 数据库连接
mybatis如何仅仅查询某个表的几个字段
【10月更文挑战第19天】mybatis如何仅仅查询某个表的几个字段
27 1
|
1月前
|
SQL Java 数据库连接
mybatis使用四:dao接口参数与mapper 接口中SQL的对应和对应方式的总结,MyBatis的parameterType传入参数类型
这篇文章是关于MyBatis中DAO接口参数与Mapper接口中SQL的对应关系,以及如何使用parameterType传入参数类型的详细总结。
31 10
|
1月前
|
SQL Java 数据库连接
Mybatis中传入不同类型的值处理方案
这篇文章讲述了在Mybatis中如何处理传入不同类型参数的情况,包括单个值、列表及Map等,并提供了相应的XML映射和Java代码示例。
72 0
|
4月前
|
Java 数据库连接 数据库
mybatis plus 更新值为null的字段
mybatis plus 更新值为null的字段
57 7
MyBatisPlus如何根据id批量查询?Required request parameter ‘id‘ for method 解决方法是看青戈大佬MybatisPlus的教程
MyBatisPlus如何根据id批量查询?Required request parameter ‘id‘ for method 解决方法是看青戈大佬MybatisPlus的教程
MybatisPlus介绍新增用户,根据id查询,引入MybatisPlus的起步依赖,增删改查最简单的写法
MybatisPlus介绍新增用户,根据id查询,引入MybatisPlus的起步依赖,增删改查最简单的写法
|
4月前
|
数据库
MybatisPlus3---常用注解,驼峰转下滑线作为表明 cteateTime 数据表中的 cteate_time,@TableField,与数据库字段冲突要使用转义字符“`order`“,is
MybatisPlus3---常用注解,驼峰转下滑线作为表明 cteateTime 数据表中的 cteate_time,@TableField,与数据库字段冲突要使用转义字符“`order`“,is
|
1月前
|
Java 数据库连接 Maven
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和MyBatis Generator,使用逆向工程来自动生成Java代码,包括实体类、Mapper文件和Example文件,以提高开发效率。
108 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。