因为国内的招聘很多对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,但是也搞懂了一些东西还是有收益的。希望能对后来者有用。