今天谈一谈我在学习MyBatis框架中遇到的问题,我们先来看异常:
遇到这个问题是我把整个代码检查了一遍,发现都没有问题,最后在检查实体类时发现没有无参构造方法,只有有参构造。如果实体类里没有有参构造方法,它会有一个默认的无参构造,而当你创建了有参构造该无参构造方法必须手动创建。
实体类:
package com.my.entity;
import java.util.Date;
// 访问日志实体类
public class AccessLog {
private int id;
private String ip;
private Date accessDatetime;
private String accessPoint;
//无参构造
// public AccessLog() {
// }
//有参构造
public AccessLog(String ip, Date accessDatetime, String accessPoint) {
this.ip = ip;
this.accessDatetime = accessDatetime;
this.accessPoint = accessPoint;
}
public AccessLog(String ip, String accessPoint) {
this.ip = ip;
this.accessPoint = accessPoint;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public Date getAccessDatetime() {
return accessDatetime;
}
public void setAccessDatetime(Date accessDatetime) {
this.accessDatetime = accessDatetime;
}
public String getAccessPoint() {
return accessPoint;
}
public void setAccessPoint(String accessPoint) {
this.accessPoint = accessPoint;
}
@Override
public String toString() {
return "AccessLog [id=" + id + ", ip=" + ip + ", accessDatetime=" + accessDatetime + ", accessPoint="
+ accessPoint + "]";
}
}
那么为什么必须要有有参构造方法呢?这就跟MyBatis框架的底层实现有关系了。MyBatis封装了JDBC,基于反射等技术。
在映射文件AccessLogMapper.xml,select标签的resultType属性值为实体类的完全限定名,当执行一个Mapped Statement操作时,MyBatis会根据你设置的resultType(返回值类型)通过反射创建该类型的对象,再将查询后的结果存入该对象。
大致过程如下:
//通过完全限定名获取该类型的Class对象
Class accessLogClass = Class.forName("com.my.entity.AccessLog");
//通过无参构造创建该类对象
AccessLog accessLog = (AccessLog) accessLogClass.newInstance();
//通过setXXX方法传入值
accessLog.setId(id);
accessLog.setIp(ip);
accessLog.setAccessDatetime(accessDatetime);
accessLog.setAccessPoint(accessPoint);
//获取该类的所有构造方法
accessLogClass.getConstructors();
MyBatis通过反射创建实体类对象时优先使用无参构造方法创建对象,如果实体类中没有无参构造方法,则会找有没有相应的有参构造方法。而我这个实体类中既没有无参也没有对应的有参构造,所以就会抛出异常。
加上无参构造方法后运行结果: