相信大家工作中都用过Mybatis,在使用Mybatis时其mapper对应的xml中若是使用select查询则必须要写resultType。如果返回值过多的情况下,我们一般都是使用实体类接受返回值,但有时返回的值比较少的时候为了较少代码中实体类的数量,我一般用Map。
但是问题来了,当resultType若为Map时,若定义了Map的泛型为String,但是数据库返回字段在库中为Number,那么就会发现虽然Map中有值,但是其类型为BigDecimal,泛型并没有起作用。
但是如果是使用实体类接收这些属性,属性的类型定义为String,那么这些属性有值以后值的类型也是为String而不是BigDecimal。
于是好奇的我去mybatis源码走了一波。结果发现:
若resultType是实体类,则会将实体类中所有的属性都拿出来,同时这些属性的数据类型也按照实体类中定义的来,然后根据这些属性名和属性的数据类型到数据库找同名同类型的字段,然后把数据库中该字段的值赋给实体类(其实就是根据java的数据类型找到对应的typeHandler,该typeHandler会将数据库的类型转换为java中的数据类型)。若碰到类型不是强一致的,则mybatis会自己判断是否能够隐式转换,例如上图我们数据库中的类型为Number,对应java中的类型应该为Long,但是我们用String来接收,这种非强一致性的也能转成功的。
若resultType是Map,则会重新构造一个新的Map,其泛型会被舍弃,然后Map默认对应的数据类型为Object,然后会直接将数据库返回的字段和属性直接映射返回到Map中。
有兴趣的同学可以自己打断点到mybatis的源码一步步跟着看看就能知道是怎么来的了,由于源码走的过程比较复杂,这里就不贴具体的源码流程了,把大致总结的结果记录一下。