今天写一个很简单的小功能,结果连续往坑里掉,难道是最近一直嘴炮出方案,画画图写写文档,好久没写代码遭报应了 o(╥﹏╥)o
一、mybatis的字段映射问题
现象是这样:
@Select("select id,member_id,device_type,device_token from device_token where member_id = #{memberID}")
List<DeviceToken> searchDeviceTokenByMemberID(@Param("memberID") Integer memberID);
使用这种注解方式检索数据,得到的结果集条数正确,但是每条记录里面,只有id这个字段有值,其他字段都是null。
这个问题的思路其实很清晰,SQL本身没问题,因为条数和ID都对的上;
至于其他字段没值,肯定是字段映射时出了问题,字段名都带下划线,而DTO(DeviceToken)里面都是小驼峰。
这个工程之前不需要访问数据库,这次新加的功能要访问几个配置表,所以肯定是添加mybatis相关配置的时候有漏掉的东西。
那么,复习一下让mybatis自动做字段映射的几种方法
- 在mybatis-config.xml中设置
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
- SQL中使用别名做转换,让别名与DTO字段名保持一致,比如上例中可以写成
@Select("select id,member_id as memberId,device_type as devictType,device_token as deviceToken from device_token where member_id = #{memberID}")
List<DeviceToken> searchDeviceTokenByMemberID(@Param("memberID") Integer memberID);
但是这样做很繁琐,字段多的时候这么搞能烦死
-
如果没用@Select注解,而是在XML中写SQL的话,当然是定义resultMap,这地球人都知道就不多写。
-
配合@Select注解,使用@Results和@Result代替resultMap。
@Select("select id,member_id,device_type,device_token from device_token where member_id = #{memberID}")
@Results(
@Result(property = "id", column = "id"),
@Result(property = "memberId", column = "member_id"),
@Result(property = "devictType", column = "device_type"),
@Result(property = "deviceToken", column = "device_token")
)
List<DeviceToken> searchDeviceTokenByMemberID(@Param("memberID") Integer memberID);
写这玩意比别名还麻烦,真有人会这么干吗?(好歹XML里的resultMap是自动生成的)
-
攻城狮这种生物,当然是怎么省事怎么来了
对于 Spring Boot 工程,直接在 application.properties 里面追加一句设定就行了:
mybatis.configuration.map-underscore-to-camel-case=true
当然肯定是先要在pom中引入stater
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>
二、没生效……
按照上面第五种方法加上一句话,美滋滋又跑了一下。
结果还是一样的错误,这不科学!
反反复复检查了半天,又跟别的一模一样配置的工程对比了一遍,哪儿哪儿都一样啊。
在这个过程中消耗了不少时间,有点小崩溃。
安静下来想了想,还是先看看底层到底发生了啥事吧,先把debug日志打开,看看输出的日志里有什么值得关注的地方,不行就只能用debug启动工程一行一行看了。
将“log4j2.xml”中的配置修改了一下
<loggers>
<root level="debug">
<appender-ref ref="Console" />
<appender-ref ref="RollingFileWarn" />
<appender-ref ref="RollingFileError" />
<appender-ref ref="RollingFileAll" />
</root>
</loggers>
输出级别从info改成了debug。
呵呵了,这个改完了也没生效,还是只输出info、warn和error。
三、调查方向反而变清晰了
也就是说log4j2.xml本身根本就没有生效,系统使用的默认配置。
这样的话,调查方向反而变清晰了。
mybatis的配置未生效,log4j的配置未生效。99%不是mybatis自己的问题了。
这两件事的共通特点是:配置都在 application.properties 里面
logging.config = classpath:log4j2.xml
mybatis.configuration.map-underscore-to-camel-case = true
试着配置了一下工程的端口号
server.port=7999
重启以后发现端口依旧是8080,坐实了问题的根源所在。
不过呢,SpringBoot中的application.properties不生效,这事可是闻所未闻。
灵光一闪,去看了一下编译后生成的target目录,再次呵呵了,这里面根本就没有 application.properties 这文件!
正常来说,pom里面做了如下配置的话,编译时resources文件夹下的各种文件肯定都会被copy到编译结果里的:
<resources>
<!-- 指定 src/main/resources下所有文件及文件夹为资源文件 -->
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
但就是偏偏没有。
唯一不太正常的地方,就是前些日子曾经随手往target目录里面放了一个文件,用于跟编译结果做比较。我使用的工作环境是IDEA,不知道这样做到底造成了什么影响。
不管怎么说,接下来的解决方法就很简单了,把target直接删掉,让IDEA重新编译,就一切正常了。
四、一点想法
这次问题排查有点哭笑不得。
说它难吧,真心啥技术上的难点都没有;
说它不难吧,可前前后后折腾了我半天时间。
想了想,以后排查问题的时候应该多点自信,像上面追加了“mybatis.configuration.map-underscore-to-camel-case=true”以后还是不行,就开始反反复复一个字一个字各种查,各种墨迹,这样看问题有点狭窄。
觉得自己写对了,但就是跑不对的话,问题没准出在一些你完全想不到的地方。
有时候不妨直接来个完全rebuild,甚至是IDEA的“Invalidate Caches”,此类操作虽然耗时间,但充其量最多十几分钟(IDEA重新建立索引时,工程大的话是要等一会的),比自己到处瞎查可快多了。
网友评论