記錄一種Mybatis的奇怪狀況

最近在幫人調試代碼的時候,發現了這樣一個問題:java

工程是Spring Boot + Mybatis,主要代碼以下:sql

xxxMapper.xml:mybatis

<resultMap id = "BaseResultMap" type = "aaa.bbb.ccc.xxxVo">
  <id column="id" jdbcType="Integer" property="id" />
  ...
</resultMap>

<select id="selectSomething" resultMap="BaseResultMap">
  select 
    id, xxx ...
  from
  where
</select>

xxxMapper.java:app

package ...

import ...

public interface xxxMapper {
  List<yyyVo> selectSomething();
  
  ...
}

xxxServiceImpl.java:ide

package ...

import ...

@Serivce
public class xxxSerivceImpl implements xxxService {

  @Autowired
  private xxxMapper xxxDao;

  @Override
  Result selectSomething(){
    ...
    List<yyyVo> list = xxxDao.selectSomething();

    foreach(yyyVo yyy : list){
        yyy.getSth();
    }
  }
  
  ...
}

你們應該已經發現了:SQL的返回值在xxxMapper.xml中被定義爲xxxVo,可是在xxxMapper.java之中卻被定義爲List<yyyVo>,而且在後面的service層使用該方法時,也把返回結果看成List<yyyVo>來操做。但奇怪的是,當sql執行結束並把結果賦值給List<yyyVo>時,並無報錯,只有當for循環中取list的每一項的值的時候,纔會拋出class cast Exception。調試

這個狀況有點奇怪,主要緣由是Java在處理泛型的時候進行了類型擦除。編譯器關注的只有xxxServiceImpl中的code

List<yyyVo> list = xxxDao.selectSomething();

對於編譯器而言,這一個賦值語句的左右兩端都是List<yyyVo>,因此能夠正常編譯經過。xml中對sql返回的數據類型定義爲xxxVo的狀況根本不被編譯器探測到。在執行代碼時,因爲泛型內部的類型是擦除的。因此mybatis把返回的數據組成List<xxxVo>賦值給list的時候,由於雙方都是List<>,也能正常執行。只有當程序從list中取出數據時,由於代碼中認爲list的每一個數據都應該是yyyVo,而實際的list時xxxVo,所以產生了class cast Exception。xml

相關文章
相關標籤/搜索