项目场景:
将数据表user中字段全部查出并封装到实体类User中。
user表字段结构
User实体类属性
// 用户id
private Integer id;
// 用户昵称
private String name;
// 用户头像地址
private String portrait;
// 注册手机
private String phone;
// 用户密码(可以为空,支持只用验证码注册、登录)
private String password;
// 注册ip
private String reg_ip;
// 是否有效用户
private Integer account_non_expired;
// 账号是否未过期
private Integer credentials_non_expired;
// 是否未锁定
private Integer account_non_locked;
// 用户状态
private String status;
// 是否删除
private Integer is_del;
UserMapper.xml
<select id="findUser" resultType="user">
select * from user
</select>
sqlMapConfig.xml
开启自动驼峰命名规则(注意这里)
<!-- 是否开启自动驼峰命名规则(camel case)映射,即从数据库列名
A_COLUMN 到属性名aColumn 的类似映射 a_name aName-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
测试类
@Test
public void testInteger(){
List<User> user = userMapper.findUser();
for (User user1 : user) {
System.out.println(user1);
}
}
以上是项目配置信息
问题描述
运行测试类,查到的字段中reg_ip、account_non_expired、credentials_non_expired、account_non_locked、is_del始终为null
"account_non_expired": null,
"credentials_non_expired": null,
"account_non_locked": null,
"status": "ENABLE",
"is_del": null,
"create_time": null,
"update_time": null
原因分析过程:
1、首先我看数据库中这几个字段都是bit(1)类型,我以为是User类中数据类型Integer不能匹配bit类型,看了几篇文章说MySql中bit用Boolean类型或者Byte类型接收,修改User类,问题依然存在。
2、继续搜索没找到相似的问题,遂只能通过调试看源码(Mybatis的源码真的很难懂),经过一下午的调试,设置了6个断点,终于查出了问题所在。
2.1 在DefaultResultSetHandler.java中有如下代码,这段代码就是把没有映射的字段封装到typeHandlerMap中,colunmName变量就是数据库查询出的字段,目前其值为reg_ip,可以发现数据库中查出来了相应的字段。
2.2 在执行到findProperty方法时,点step into,会进入MetaObject.java类,一路继续step into,最终进到MetaClass.java,最终执行的方法如下图,其中name就是上文的propertyName即colunmName。
可以看到该方法会判断是否使用驼峰命名映射,由于在Mybatis配置中开启了驼峰命名,这里会把数据库中字段中的 ‘_’ 给删掉,最中name属性变成了regip.
再返回DefaultResultSetHandler.java中,判断User类中有没有regip属性,结果自然是失败,因为实体类中是reg_ip.
问题就出在Mybatis的自动驼峰命名规则。
解决方案:
建议:
1、如果Mybatis配置开启了自动驼峰命名规则,不要管数据库字段是什么,实体类中始终使用驼峰命名来写相关属性。
2、如果Mybatis没开启驼峰命名规则,实体类中属性最好与数据库中字段保持一致,建议直接复制粘贴,避免敲错。