ibatis中得resultMap得property属性值得大小写
总结
今天在公司写代码过程中,一不小心把sql得xml中得resultMap得property属性值得首字母写成大写,导致编译报错。百思不得其解,现我做几个实验来验证我的想法。
准备一个实体类和一段sql
User实体类
package com.jsyy.jrsc.entity;
public class User {
private int id;
private String user_name;
private String user_no;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUser_name() {
return User_name;
}
public void setUser_name(String user_name) {
this.User_name = user_name;
}
public String getUser_no() {
return user_no;
}
public void setUser_no(String user_no) {
this.user_no = user_no;
}
}
执行sql返回结果集的封装
<resultMap id="userResult" class="user" >
<result column="id" property="id" jdbcType="INTEGER" />
<result column="user_name" property="user_name" jdbcType="VARCHAR" />
<result column="user_no" property="user_no" jdbcType="VARCHAR" />
</resultMap>
实验一:改变实体类的大小写
改变User实体类里面的属性user_name的首字母U,换成大写。启动项目编译成功
七月 10, 2020 9:47:49 下午 org.apache.catalina.core.StandardService startInternal
信息: Starting service [Tomcat]
七月 10, 2020 9:47:49 下午 org.apache.catalina.core.StandardEngine startInternal
信息: Starting Servlet engine: [Apache Tomcat/9.0.35]
七月 10, 2020 9:47:49 下午 org.apache.catalina.core.ApplicationContext log
信息: Initializing Spring embedded WebApplicationContext
实验二:改变sql的resultMap的property属性值得大小写
把user_name改成User_name
<result column="user_name" property="User_name" jdbcType="VARCHAR" />
编译报错
Caused by: java.lang.RuntimeException: 加载sqlmap-文件出错(load sqlmap- file wrong). Cause: java.lang.RuntimeException: Error occurred. Cause: com.ibatis.common.xml.NodeletException: Error parsing XML. Cause: java.lang.RuntimeException: Error parsing XPath ‘/sqlMapConfig/sqlMap’. Cause: com.ibatis.common.xml.NodeletException: Error parsing XML. Cause: java.lang.RuntimeException: Error parsing XPath ‘/sqlMap/resultMap/result’. Cause: com.ibatis.common.beans.ProbeException: There is no WRITEABLE property named ‘User_name’ in class ‘com.jsyy.jrsc.entity.User’
结论
实体类属性的无论是大小写还是驼峰,都不会影响。但是sql结果集中的property属性值必须要小写。
深入底层分析
这个报错并不是在封装结果集的时候报的错,因为编译时候并不会执行sql。只有请求打过来,执行sql,采取封装结果集。而且我看了源码更加确定这一点。
// 字段名
String columnName = metaData.getColumnName(i);
// 字段的值
Object value = resultSet.getObject(columnName);
//使用反射或者内省,根据数据库表和实体的对应关系,完成封装
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClass);
Method writeMethod = propertyDescriptor.getWriteMethod();
writeMethod.invoke(o,value);
最后的猜测
我没把整个源码都放过来,但是看value的值通过反射来获取,然后通过内省方法,set+首字母大写转换(“value”),查找对应字符串的方法,然后反射调用方法,把属性set进去。
编译报错,应该是解析xml的时候报错,我猜测,在解析到resultMap的时候,自动把属性值转成user_name而非User_name,然后再到实体类里面找这个属性值,发现没有,然后抛异常。个人猜测,没有去验证和深入底层再去看,如果有什么不对的地方,请各位大佬提出,万分感谢。