1、首先先了解下Mybatis框架的入门案例
2、Mybatis执行流程
1、当执行 builder.build(in);语句时,会从文件流对象in 指定的文件中,通过dom4j对XML文件进行解析,解析的内容存放到Configuration对象中,(可以拿到数据库连接信息如:url、username、password等,然后通过SqlMapConig.xml中的mapper标签,可以得到 程序采用的映射方式是注解或者配置文件,并且可以得到映射的全限定类名)
(以上是两个been的属性)
2、当执行session.getMapper(IUserDao.class);时,看下图,是对IuserDao中的方法进行增强,增强的方法写在了MapperProxy代理类中:
MapperProxy代理类中的invoke方法:
可以看到在invoke方法中,可以拿到调用方法的方法名(上图的findAll方法)和方法所在的全限定类名,组合成Key之和就可以在Mappers中得到下图中的Mapper对象,Mapper对象中存放着(要封装结果集的实体类全限定类名,和要执行的SQL语句)
MapperProxy代理类的invoke方法里边的Executor类(是对SQL语句的执行,和结果集的封装)
public class Executor {
public <E> List<E> selectList(Mapper mapper, Connection conn) {
PreparedStatement pstm = null;
ResultSet rs = null;
try {
//1.取出mapper中的数据
String queryString = mapper.getQueryString();//select * from user
String resultType = mapper.getResultType();//com.itheima.domain.User
Class domainClass = Class.forName(resultType);
//2.获取PreparedStatement对象
pstm = conn.prepareStatement(queryString);
//3.执行SQL语句,获取结果集
rs = pstm.executeQuery();
//4.封装结果集
List<E> list = new ArrayList<E>();//定义返回值
while(rs.next()) {
//实例化要封装的实体类对象
E obj = (E)domainClass.newInstance();
//取出结果集的元信息:ResultSetMetaData
ResultSetMetaData rsmd = rs.getMetaData();
//取出总列数
int columnCount = rsmd.getColumnCount();
//遍历总列数
for (int i = 1; i <= columnCount; i++) {
//获取每列的名称,列名的序号是从1开始的
String columnName = rsmd.getColumnName(i);
//根据得到列名,获取每列的值
Object columnValue = rs.getObject(columnName);
//给obj赋值:使用Java内省机制(借助PropertyDescriptor实现属性的封装)
PropertyDescriptor pd = new PropertyDescriptor(columnName,domainClass);//要求:实体类的属性和数据库表的列名保持一种
//获取它的写入方法
Method writeMethod = pd.getWriteMethod();
//把获取的列的值,给对象赋值
writeMethod.invoke(obj,columnValue);
}
//把赋好值的对象加入到集合中
list.add(obj);
}
return list;
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
release(pstm,rs);
}
}
private void release(PreparedStatement pstm,ResultSet rs){
if(rs != null){
try {
rs.close();
}catch(Exception e){
e.printStackTrace();
}
}
if(pstm != null){
try {
pstm.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
总结: