这一篇简单查看下mybatis的执行流程及核心的类。
上文中查询的代码:
InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
City city = sqlSession.selectOne("com.hhg.jerry.dao.CityDao.getById",1L);
对框架使用者而言:
1、指定配置文件生成InputStream
2、根据InputStream构建SqlSessionFactory
3、SqlSessionFactory打开SqlSession
4、SqlSession执行crud(create、retrive、upate、delete)
下面根据mybatis源码说明下步骤 2、3、4
step2:InputStream经过XMLConfigBuilder解析为Configuration对象,通过configuration构造出DefaultSqlSessionFactory。构建configuration时解析的xml元素如下:
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
注意到我们现在仅仅配置了environments和mappers,Mybaits就能够运行的。如何解析每个element建议先别看,因为我们要了解的是主流程,而不是细节。
step3:SqlSessionFactory创建SqlSession,重载了几个方法,但最终调用的是一个方法:
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
参数: ExecutorType->枚举类(具体不清楚) TransactionIsolationLevel->枚举类 隔离级别 autoCommit->自动提交
函数体:先构建一个Transaction,通过transaction构建Executor,executor又构建了DefaultSqlSession
到此只看到了一些外表,先不看细节,继续往下看。
step4: SqlSession的查询,sqlSession.selectOne("com.hhg.jerry.dao.CityDao.getById",1L);简单跟进去后就到这里了:
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
根据statement("com.hhg.jerry.dao.CityDao.getById")拿到MappedStatement对象,SqlSession的executor去继续query,此executor是CachedExecutor,但我们并没有配置缓存啊,先继续debug就到了BaseExecutor的query方法中:
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
localCache.get,还是从缓存中取,取不到就queryFromDatabase,我们再debug方法queryFromDatabase,最终到了SimpleExecutor类中(CacheExcutor的delegate就是SimpleExecutor)的doquery方法:
@Override
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());
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
StatementHandler是什么?一会再看他,prepareStatement方法返回了Statement(JDBC的接口):
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());
handler.parameterize(stmt);
return stmt;
}
咦,这不是JDBC的东西了吗?终于找到你,回到SimpleExecutor的doquery方法,最后return了handler.query,来看下这个方法,在PrepareStatementHandler类中:
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.<E> handleResultSets(ps);
}
还是JDBC的那一套,只不过用resultHandler处理了查询结果,后续就是一层层的返回这个结果了
到这里mybaits的执行流程就被我们走马观花的看了一遍,总结一下:Session -> Executor -> JDBC -> ResultHandler -> 结果 ,细节暂时都不清楚。配置文件也没配全,也不清楚。下一步就是单独的功能点分析,会深入这些细节,同时配置也会全起来
还记得流程中有个CacheExecutor和localCache.get吗? 他们干吗用的? 且看下回分解,mybaits缓存