参考网址:《深入浅出Mybatis系列(十)—SQL执行流程分析(源码篇)》 MyBatis 执行一次指令的过程有两个阶段,获取 Mapper与执行语句。
**SqlSession 是 MyBatis 的灵魂。**获取 Mapper 的操作也是在 SqlSession 接口中执行的。但首先应该考虑的是 SqlSession 如何创建。
首先,SqlSessionFactoryBuilder 用来构建 SqlSessionFactory。
通常由于我们使用的是 Spring 与 Mybatis 共同使用,所以使用到了 org.apache.ibatis.spring 中的 SqlSessionFactoryBean。在该类中指定一个 xml 文件,同时 SqlSessionFactoryBean 中有一个 SqlSessionFactoryBuilder。将 XML 文件传入 builder,即可构建 SqlSessionFactory。
SqlSessionFactory 全局基本上只有一个(如果有多个,说明系统设计是有问题的),通过 SqlSessionFactory 构建 SqlSession。SqlSessionFactory 最重要的方法就是 openSession() 方法。通过 openSession() 方法一系列的调用,最终会创建一个包装了 Statement 的 executor,以及一个 DefaultSqlSession。
每一个线程都有一个 SqlSession,用于执行 Sql 的增删改查、事务、获取 Mapper 接口等基本操作。
获取 Mapper 接口也是 SqlSession 的主要功能。Mapper.getMapper() 方法执行过程中,经过多次调用,在 MapperProxyFactory 中通过代理方式 newInstance() 真正的获取 Mapper 方法。
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
//动态代理我们写的dao接口
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
获取了 Mapper 之后就可以执行语句了。
获取的 Mapper 接口并不完全是接口本身,而是被 MapperProxy 类代理的接口。MapperProxy 是实现了动态代理接口 InvocactionHandler 的实现类,所以执行这里的 query 语句也是通过代理类通过反射调用执行的。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
//主要交给MapperMethod自己去管
return mapperMethod.execute(sqlSession, args);
}
在 MapperMethod 的 execute 方法中进行判断,准备真正执行语句,执行过程还是会交给 SqlSession。比如执行 selectList 方法,selectList 方法会在前面 SqlSessionFactory 中构建的 executor 中调用 query 方法,然后再经过层层调用,到达 doQuery 方法。doQuery 方法中获取到了 StatementHandler,执行 query 方法:
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
//StatementHandler封装了Statement, 让 StatementHandler 去处理
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
在 StatementHandler 中执行的 query 如下:
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
// 到此,原形毕露, PreparedStatement, 这个大家都已经滚瓜烂熟了吧
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
// 结果交给了ResultSetHandler 去处理
return resultSetHandler.<E> handleResultSets(ps);
}
最后到了 PreparedStatement 的执行,就到了 JDBC 真正执行的地方。至此一次 SQL 执行流程完毕。