Mybatis Type Handler 为 null的坑

2,644 阅读3分钟

因为国内的招聘很多对Mybatis有要求,虽然我大致知道这个工具是做什么用的,但是我想改变喜欢看和理解但懒得动手操作状态。这两周在写代码用Mybatis。 我用注解和mapper很轻松的实现了对单个类的读写,但是当我用@One 注解实现多对一的查询时程序一直报错,错误是

Type handler was null on parameter mapping for property 'species'. It was either not specified and/or could not be found for the javaType (org.example.mybatis.Species) : jdbcType (null) combination.

具体的错误是

Exception in thread "main" java.lang.IllegalStateException: Type handler was null on parameter mapping for property 'species'. It was either not specified and/or could not be found for the javaType (org.example.mybatis.Species) : jdbcType (null) combination.
	at org.apache.ibatis.mapping.ParameterMapping$Builder.validate(ParameterMapping.java:117)
	at org.apache.ibatis.mapping.ParameterMapping$Builder.build(ParameterMapping.java:104)
	at org.apache.ibatis.builder.SqlSourceBuilder$ParameterMappingTokenHandler.buildParameterMapping(SqlSourceBuilder.java:146)
	at org.apache.ibatis.builder.SqlSourceBuilder$ParameterMappingTokenHandler.handleToken(SqlSourceBuilder.java:89)
	at org.apache.ibatis.parsing.GenericTokenParser.parse(GenericTokenParser.java:76)
	at org.apache.ibatis.builder.SqlSourceBuilder.parse(SqlSourceBuilder.java:51)
	at org.apache.ibatis.scripting.defaults.RawSqlSource.<init>(RawSqlSource.java:46)
	at org.apache.ibatis.scripting.xmltags.XMLLanguageDriver.createSqlSource(XMLLanguageDriver.java:61)
	at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.buildSqlSourceFromStrings(MapperAnnotationBuilder.java:608)
	at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.buildSqlSource(MapperAnnotationBuilder.java:597)
	at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.lambda$parseStatement$2(MapperAnnotationBuilder.java:303)
	at java.util.Optional.ifPresent(Optional.java:159)
	at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.parseStatement(MapperAnnotationBuilder.java:302)
	at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.parse(MapperAnnotationBuilder.java:132)
	at org.apache.ibatis.binding.MapperRegistry.addMapper(MapperRegistry.java:72)
	at org.apache.ibatis.session.Configuration.addMapper(Configuration.java:895)
	at org.example.mybatis.MybatisDemo.initMybatis(MybatisDemo.java:41)
	at org.example.mybatis.MybatisDemo.main(MybatisDemo.java:19)

我的数据很简单,一个Pet类型,一个Species类型

public class Pet {  
    public String name;  
    public Species species;  
    public String sex;  
    public LocalDate dob;  
}

public class Species {  
    public String name;  
    public String description;  
    public String origin;  
}

我的mapper也一样简单

public interface PetMapper {  
    String selectAll = "SELECT * FROM pet";  

    @Select(selectAll)  
    @Results(value = {  
    @Result(property = "name", column = "name"),  
    @Result(property = "species", column="species", one=@One(select="org.example.mybatis.SpeciesMapper.getSpecies")),  
    @Result(property = "sex", column = "sex"),  
    @Result(property = "dob", column = "birth")  
    })  
    List<Pet> selectAll();  

    @Insert("INSERT into pet values (#{name}, #{species}, #{sex}, #{dob})")  
    void save(Pet pet);  
}

public interface SpeciesMapper {  
    @Select("select name, description, origin from species where name = #{name}")  
    @Results (value={  
    @Result(property="name", column="name"),  
    @Result(property="description", column="description"),  
    @Result(property="origin", column="origin")  
    })  
    Species getSpecies(String name);  
}

我用sellectAll() 方法就出现上述的错误,在网上找了很久也没有有用的解决方法,最后我看到一篇文章说重名问题,我就想是不是Pet里面的species变量和Species类型或者species表重名了,所以我把变量改短成spe结果程序就可以运行了。虽然可以运行了但是我觉得重名这个理论解释不通,况且我的SpeciesMapper的作用就是告诉程序如何来获取species这个变量,为什么说 type handler是空的呢?

于是我尝试了把spe改回species再把Species类改成Wuzhong和把 species表改成wuzhong,还是一样报错。无奈之中我把PetMapper里面没有用到的save() 方法删除再运行结果就好了!

这是怎么回事!我的程序里面压根没有用过这个方法。 我仔细分析了一番发现那个错误是在程序添加mapper的时候发生的,并不是执行selectAll的时候发生的。而且它的query语句是要把传入的 pet里面的 species 变量(Species 类型)直接存入表中,所以mybatis 需要 Species 类型的 type handler来把它转化成数据库能存的类型! 这个query语句是我先前写的那时候 species变量还只是String类型

还有一点为什么我之前把变量名改成 spe就没问题呢?我的解释是save 方法的query里面的 #{species} 是直接被忽略了,因为Pet并不包含这个子变量。Mybatis 在这个地方又毫不计较!

填这个坑花了好多时间,让我一度想放弃学习mybatis,但是也搞懂了一些东西还是有收益的。希望能对后来者有用。