[Mybatis]Mybatis動作フロー分析
15955 ワード
機会がMybatisに注目しているので、本論文ではMybatisの全体的な実行プロセスを探ってみます.
Mybatisの例
Sql Session Factory
このインターフェースのデフォルトの実装クラスはDefault Sql Session Factoryです.
このインターフェースのデフォルトの実装クラスはDefault Sql Sessionで、上で生成されたSql Sessionはこのクラスのオブジェクトです.
Mybatisの実行コアは、Exectorにあり、いくつかの実装クラスがあり、一括実行などは、このインターフェースで実現されるものであり、本稿では、SimpleExectorの全体的な実装クラスのみに注目して、簡単なクエリである.
本当のSimpleExectorを呼び出す前に、MybatisはCachingExectorをも呼び出しました.コードは以下の通りです
Mybatisの例
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(inputStream);
SqlSession sqlSession = factory.openSession();
sqlSession.selectList("selectAllUser");
sqlSession.close();
Mybatisは上のように、前の3行のコードはスキャンxmlの情報を登録して、後のために使用するべきです.私達が重点的に注目しているのは中間の2行です.これらはどうやって完全なクエリを実現しますか?上記のfactoryはデフォルトでDefault Sql Session Factoryというカテゴリーです.このようにSql Sessionを作成します.SQL操作はSql Sessionで実行されます.Sql Session Factory
このインターフェースのデフォルトの実装クラスはDefault Sql Session Factoryです.
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;//
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
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);
// Executor, SimpleExecutor,SqlSession Executor SQL 。
final Executor executor = configuration.newExecutor(tx, execType);
// Executor SqlSession。
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();
}
}
}
Sql Sessionこのインターフェースのデフォルトの実装クラスはDefault Sql Sessionで、上で生成されたSql Sessionはこのクラスのオブジェクトです.
public class DefaultSqlSession implements SqlSession {
private Configuration configuration;
// executor CachingExecutor, executor SQL , executor , ,mybatis
private Executor executor;
private boolean autoCommit;//
private boolean dirty;
@Override
public List selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
// MappedStatement ,MappedStatement SQL ,
MappedStatement ms = configuration.getMappedStatement(statement);
// MappedStatement CachingExecutor
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();
}
}
}
ExectorMybatisの実行コアは、Exectorにあり、いくつかの実装クラスがあり、一括実行などは、このインターフェースで実現されるものであり、本稿では、SimpleExectorの全体的な実装クラスのみに注目して、簡単なクエリである.
本当のSimpleExectorを呼び出す前に、MybatisはCachingExectorをも呼び出しました.コードは以下の通りです
public class CachingExecutor implements Executor {// , 。
// SimpleExecutor,
private Executor delegate;
private TransactionalCacheManager tcm = new TransactionalCacheManager();
@Override
public List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameterObject);
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
@Override
public List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
// CachingExecutor , , , 。
Cache cache = ms.getCache();// ms
if (cache != null) {//
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, parameterObject, boundSql);
@SuppressWarnings("unchecked")
List list = (List) tcm.getObject(cache, key);
if (list == null) {
list = delegate. query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
//
return delegate. query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
}
上記の分析ではSQLの実行は最終的にはSimpleExectorによって実行されることを知っています.SimpleExectorの構造を見てください.org.apache.ibatis.executor.Executor
org.apache.ibatis.executor.BaseExecutor
org.apache.ibatis.executor.SimpleExecutor
BaseExectorは抽象的なタイプで、Exectorインターフェースを実現しました.public abstract class BaseExecutor implements Executor {
@SuppressWarnings("unchecked")
@Override
public List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List list;
try {
queryStack++;
list = resultHandler == null ? (List) localCache.getObject(key) : null;
// , CacheExecutor , 。
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {//
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
//
private List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List list;
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
// ,doQuery() , 。
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
// ,
protected abstract List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
throws SQLException;
}
サブクラスのSimpleExectorを見てください.これがクエリーの真の実装クラスです.public class SimpleExecutor extends BaseExecutor {
@Override
public List 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);
// Statement
stmt = prepareStatement(handler, ms.getStatementLog());
// stmt, Statement query() 。
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection);
handler.parameterize(stmt);
return stmt;
}
}
最後にSimpleStation Handlerを見て、どうやってクエリが実現されますか?public class SimpleStatementHandler extends BaseStatementHandler {
@Override
public List query(Statement statement, ResultHandler resultHandler) throws SQLException {
String sql = boundSql.getSql();// SQL
statement.execute(sql);// , , jdbc 。
return resultSetHandler.handleResultSets(statement);
}
}
本論文では、Mybatis全体の動作手順を迅速に理解するために、exectorインターフェースのような多くの実装クラスが省略されています.この文では一つしか与えられていません.