springboot学习笔记二:springboot+mybatis踩坑小结

为什么使用springboot+mybatis?
这个问题感觉没什么提问价值,但是关于“spring的坑”这个话题向来比较沉重,所以咱们先闲谈一下这个问题以缓解气氛。
springboot相比spring的先进之处有很多,比如对第三方插件的强大支持,内嵌式web服务器(tomcat,jetty),提供注解式sql语句简化dao层编码以及自动配置等等一大堆。想想当初的SSM框架要写mybatis-config.xml+springContext.xml+一大坨糟心的mapper.xml,springboot简直就是贴心小棉袄了啊。既然如此为什么还有springboot+mybatis这种东西的存在呢:mapper.xml文件可以通过标签(set where if等)实现动态sql语句,当springboot离开了mybatis的mapper文件就失去了这个便利性(纯属个人杜撰)。闲谈至此,如果你在实际项目中没有动态sql语句的需求,可以跳过以下内容,直接选择springboot框架。
言归正传,下面记录一下我在使用这个框架过程中遇到的几个问题以及解决方案。

一、 在service层使用@Autowired注入dao层bean时,报错找不到我们想要在dao层返回的entity类:
org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.ibatis.session.SqlSessionFactory]: Factory method ‘sqlSessionFactory’ threw exception; nested exception is org.springframework.core.NestedIOException: Failed to parse mapping resource: ‘file [D:\intellij_workspace\springbootTest\target\classes\mapper\userInfoMapper.xml]’; nested exception is org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The XML location is ‘file [D:\intellij_workspace\springbootTest\target\classes\mapper\userInfoMapper.xml]’. Cause: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias ‘UserInfo’. Cause: java.lang.ClassNotFoundException: Cannot find class: UserInfo

可能原因:mapper文件中方法返回值即resultType的值配错了
解决方案
1.这里需要正确地写出entity类的全路径,注意是全路径!像这样:


spring会自动根据你配置的type-aliases-package到相应的路径下找名为UserInfo的类,然后自动组装返回值。

二、注入dao层bean时,报错未绑定XXXDao(大致是这个意思?)
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.mjj.springboot.dao.UserInfoDao.getUserInfo…
可能原因
1.没有配置mappper.xml文件的路径,spring不知道你的dao层接口跟哪里的mapper文件进行映射
解决方法: 在项目的配置文件 application.properties中添加配置:
mybatis.mapper-locations=classpath:mapper/*.xml
此处的mapper/*.xml就是你放置mapper.xml文件的路径,*指模糊匹配,程序员都知道 。需要注意的是,maven项目中,Java,test、resource都不算包的路径,该路径统统是项目的根路径。有人习惯把mapper.xml 文件放在Java路径中跟它所映射的mapper.java放一起,个人更倾向放在resource中,二者区别及需要注意的地方另请查阅相关资料。
2.mapper.xml文件中的 namespace项跟其要映射的dao层类的路径不匹配 。
解决办法:这种错误很好检验,光标移动至namespace引号中的内容,摁住ctl键+鼠标点击。如果配置正确,此时会跳转到对应的映射类上,否则就是这里配置的路径错误。

 

三、@mapper的使用
mapper.xml文件内容写对,路径配置正确接下来就是dao层注入的问题了,在spring boot中,dao层的注解采用@Mapper,使用不当的报错:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ‘com.mjj.springboot.dao.UserInfoDao’ available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1646)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1205)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1166)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593)
… 46 common frames omitted
解决办法
1.在对应的dao层上加注解@Mapper(不是@Repository)
2.如果dao层的类太多,你又不想逐个加@Mapper,springboot也是替我们想了办法的,就是在项目的启动类(图标是个小电源,有@SpringbootApplication王者标志)上加注解:

@MapperScan("com.mjj.springboot.dao")

需要注意的是,此处是指dao层的java文件,即dao层接口而不是xml文件本身,且只对该路径下的接口进行扫描并注入。加了这个注解后,dao层的类上就不需要加bean注入的注解了。

四、resultType返回list类型,报错不支持的集合操作
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: java.lang.UnsupportedOperationException
### The error may exist in file [D:\intellij_workspace\springbootTest\target\classes\mapper\SzgjjDrwMapper.xml]
### The error may involve com.mjj.springboot.dao.SzgjjDrwInfDao.getDRWInfo
### The error occurred while handling results
### SQL: select count(GJJNBR) from GSL.TAB_DRWINFO where GJJNBR= ? and DRWDAT = ?
### Cause: java.lang.UnsupportedOperationException
可能原因:把list作为resultType的值了,目前mybatis的resultType并不支持集合类型。 只有resultMap可以灵活定义返回值类型为map
解决方案:如果是想返回List类型的值 ,只需要将返回值定义为 resultType=“UserBean” dao层对应的方法上返回值定义为List即可 mybatis 会自动识别并将多条UserBean存入list中返回。

五、关于resultType和resultMap,常见报错:
org.apache.ibatis.builder.IncompleteElementException: Could not find result map com.mjj.springboot.bean.UserInfo

Caused by: java.lang.IllegalArgumentException: Result Maps collection does not contain value for com.mjj.springboot.bean.UserInfo
at org.apache.ibatis.session.Configuration$StrictMap.get(Configuration.java:888)
at org.apache.ibatis.session.Configuration.getResultMap(Configuration.java:640)
at org.apache.ibatis.builder.MapperBuilderAssistant.getStatementResultMaps(MapperBuilderAssistant.java:344)
… 46 more
可能原因:本意想返回一个entity类,却误将resultType写成了resultMap,或者本意确实要用resultMap,但是resultMap标签中配置的id标签跟resultMap=""中的值不一致,甚至压根儿忘了写resultMap标签。
resultMap标签的写法示例:


  
  
	

个人暂时没有发现resultMap的妙用,觉得是个挺鸡肋的标签,因为它仍需要在代码中有对应的entity类,即type所映射的类,同时还要将所有的属性重复一遍,遇到字段多的时候实在麻烦,唯一的用处是:你跟设计数据库的同事意见不合,觉得他起的字段名不好,你代码里对应的entity属性名跟他起的不一样,或者数据库的字段太多,你只想要一部分封装到entity里去,这时候resultMap就派上用场了,“偷梁换柱”也好“偷工减料”也好都能在这个标签里悄悄进行。如果没有此类需求,你可以直接用resultType=“Entity” 或者resultType=“map” (此时dao层返回值直接就是Map或者List)。

六、测试类的注解问题
可能报错:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘com.mjj.springboot.daoTest.CutInfoDaoTest’: Unsatisfied dependency expressed through field ‘szgjjCutInfDao’; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ‘com.mjj.springboot.dao.SzgjjCutInfDao’ available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
可能原因
1.测试类没有正确地添加注解:

@RunWith(SpringRunner.class)
@SpringBootTest

2.由于各种奇葩原因,你的项目里有两个Application类,此时@SpringBootTest就晕头了,它不知道它应该去匹配哪一个入口类,此时你只需要指定正确的入口类就好了:

@RunWith(SpringRunner.class)
@SpringBootTest(Application1.class)

当测试类很多又不想逐一添加的时候 ,可以写一个测试基类 ,在测试基类上添加正确的注解,其他的测试类都继承该基类 ,就不用一个一个写注解了,简化代码同时方便测试类注解的管理。

七、一个超轻松的问题
报错:
java.sql.SQLException: The server time zone value ‘?D1ú±ê×?ê±??’ is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.
解决:在项目的配置文件 application.properties中添加配置:

spring.datasource.url =jdbc:mysql://99.10.50.201:3306/GSL?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC

八、配置文件
前面有说过spring boot相比spring的一大优势是自动配置,自动配置就是不需要像spring一样写很多的配置文件了,它只需要一个application.properties就好了,也就是不需要mybatis.xml springContext.xml等等。其他的配置交由各式各样的注解去完成。我作为一个反应不灵活的程序员,实在深受各种配置文件的困扰,所以只愿意掌握诸多方法中最简单的一个。其次,本人初学springboot,文中所提皆是基础,且还有诸多问题不甚清楚,后续若有领悟会回来完善更正。若有大神误入,发现错误的地方万望不吝赐教。

你可能感兴趣的:(Java后端框架)