使用Mybatis时dao层泛型失效的问题

前几天在项目中遇到一个问题,排查了许久才解决问题,记录下来:

  • 问题重现

使用Mybatis时dao层泛型失效的问题

如上图,首先我们在dao层定义了一个接口方法,同时使用泛型规定返回的结果类型为List<Map<String,String>>。

使用Mybatis时dao层泛型失效的问题

然后在service层中调用该方法时,在序号1处将dao层返回的结果集放入另一个Map集合中,根据dao层定义的List<Map<String,String>>结果集类型,countMap中应该是键值对应该均为字符串类型;但是在序号2处,使用字符串类型的键来获取值时,num的值为null,与期望的结果不同。但是根据代码逻辑看不出有什么问题,在使用debugger发现了问题的原因。问题如下:

使用Mybatis时dao层泛型失效的问题

通过debugger发现,countMap中值的实际类型为Map<Integer,Long>,所以当我们使用Sting类型的键去获取值时就会出现null,因为Map中键就不是字符串类型,因此使用字符串类型的键是获取不到值的。

  • 问题思考

我们在dao层中明确的定义了返回类型为List<Map<String,String>>,为什么接收到的结果集的实际类型却为Map<Integer,Long>呢?

经过检查代码,发现最有可能是在xml文件中出现问题,因为我在xml文件中并没有使用实体映射类来接收而是使用map类型来接收。

通过查找资料,问题果然是由于返回类型为map造成的。

使用Mybatis时dao层泛型失效的问题

使用Mybatis时dao层泛型失效的问题

由于我们使用map类型来接收,没有使用实体映射类来接收。而Mybatis默认返回的List<Map<String, Object>>,是以每个字段name作为key,字段的值作为value,放入至Map<String,Object>的List数组。实际返回类型实际上跟数据库字段的类型有关系,返回字段类型基本可以看做就是数据库字段类型; 而并不是我们dao层接口定义的Map<String,Stirng>

那么,又有一个问题来了;既然返回的数据类型跟我们的定义的泛型类型不一致,为啥不报错?

原因是泛型只存在于编译时期,当编译完成之后是会进行泛型擦除的。而dao层返回数据是在运行时发生的(准确说是在你调用这个方法的时候才有数据返回),而在这个时候泛型已经不存在了,实际上就是List集合,是不会报错的。

  • 问题总结:

1.dao层定义的泛型类型实际上是没有用的,因为数据是在运行期发生的,这个时候泛型已经没有了。

2.如果在dao层使用List<PO>这样的实体集合进行接收,一定要在xml文件中定义实体类与数据库字段的映射。

3.如果在xml中定义了返回类型为map类型来接收时,dao层一定要用Map<Stirng,Object>类型来接收,然后在service层转换成自己期望的类型继而进行下一步的操作。