MyBatis初始化完後,org.apache.ibatis.session.Configuration
中,會有已經初始化完的數據,供後續的執行:java
MapperRegistry
的實例,有一個屬性Map<Class<?>, MapperProxyFactory<?>> knownMappers
:sql
MapperProxyFactory
對象,是Mapper代理類MapperProxy
的工廠,建立MapperProxy
對象執行Mapper類中定義的方法。類型是Map<String, MappedStatement>
:apache
MappedStatement
對象的id,如'com.xxx.yyy.model.UserMapper.selectList';MappedStatement
對象。MyBatis分三個步驟執行查詢過程:緩存
DefaultSqlSession
;session.getMapper(UserMapper.class)
;userMapper.findList()
。DefaultSqlSessionFactory.openSession
:session
public SqlSession openSession(boolean autoCommit) {
// 第一步
// Configuration中:defaultExecutorType = ExecutorType.SIMPLE
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit);
}
// 第二步
//openSessionFromDataSource關鍵代碼:
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
複製代碼
Executor從Configuration.newExecutor
方法中建立:app
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
複製代碼
newExecutor
的執行過程以下:ide
SimpleExecutor
;CachingExecutor
對象;interceptorChain.pluginAll
加入攔截器Interceptor
列表。DefaultSqlSession
從Configuration.mapperRegistry
中獲取Mapper的實現對象:this
// 第一步
// DefaultSqlSesison:
public <T> T getMapper(Class<T> type) {
return configuration.<T>getMapper(type, this);
}
// 第二步
// Configuration:
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
// 第三步
// MapperRegistry:
// 從屬性knownMappers中獲取MapperProxyFactory對象,獲取到後執行newInstance獲取MapperProxy,即Mapper類的實現對象。
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
// 第四步
// MapperProxyFactory 建立MapperProxy對象
protected T newInstance(MapperProxy<T> mapperProxy) {
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);
}
複製代碼
由上面MapperProxyFactory
代碼可知,每次執行session.getMapper
都會建立MapperProxy
對象及其代理對象,因此應避免屢次調用session.getMapper
。spa
MyBatis使用JDK代理方式,MapperProxy
實現了InvocationHandler
接口,因此Mapper接口類的實現方法,是在MapperProxy.invoke
方法裏執行。代理
invoke
中,獲取或建立一個MapperMethod
對象,而後執行MapperMethod.execute
方法。
//// 獲取MapperMethod對象
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
//// 執行execute
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
複製代碼
MapperMethod
有兩個屬性:
private final SqlCommand command;
private final MethodSignature method;
複製代碼
SqlCommand
有兩個屬性:
SqlCommand建立時,會從Configuration中獲取MappedStatement對象,獲取到則用於name和type的賦值:
String statementId = mapperInterface.getName() + "." + methodName;
if (configuration.hasStatement(statementId)) {
return configuration.getMappedStatement(statementId);
}
複製代碼
private final boolean returnsMany; // configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray()
private final boolean returnsMap; //
private final boolean returnsVoid; // void.class.equals(this.returnType)
private final boolean returnsCursor; // org.apache.ibatis.cursor.Cursor.class.equals(this.returnType)
private final Class<?> returnType;
//////
private final ParamNameResolver paramNameResolver; // new ParamNameResolver(configuration, method)
複製代碼
根據command.type
,判斷執行的操做:
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}
複製代碼
在execute調用的
executeFor*
方法中,最終調用的是sqlSession.select*
方法。
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
// 第一步,從Configuration中取出MappedStatement對象
// statement : interfaceName + "." + methodName
MappedStatement ms = configuration.getMappedStatement(statement);
// 第二步,執行查詢
// executor : 前面Configuration.newExecutor建立的executor,默認SimpleExecutor
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();
}
}
複製代碼
executor.query的調用鏈:
BaseExecutor.query -> BaseExecutor.queryFromDatabase -> SimpleExecutor.doQuery
SimpleExecutor.doQuery:
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();
// 第一步 建立RoutingStatementHandler
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 第二步 調用StatementHandler.prepare建立Statement
stmt = prepareStatement(handler, ms.getStatementLog());
// 第三步 執行StatementHandler.query
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
複製代碼
configuration.newStatementHandler中建立的是RoutingStatementHandler
,而後設置攔截器:
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
複製代碼
RoutingStatementHandler
是一種委派模式,根據MappedStatement.statementType
的不一樣,返回不一樣的StatementHandler
實現類:
// 代理
private final StatementHandler delegate;
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
switch (ms.getStatementType()) {
case STATEMENT:
delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}
}
複製代碼
建立java.sql.Statement
對象,調用鏈:
RoutingStatementHandler.prepare -> BaseStatementHandler.prepare -> PreparedStatementHandler.instantiateStatement
instantiateStatement
是BaseStatementHandler
的抽象方法,供子類實現。
// PreparedStatementHandler
protected Statement instantiateStatement(Connection connection) throws SQLException {
if (mappedStatement.getResultSetType() != null) {
return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
} else {
return connection.createStatement();
}
}
複製代碼
有了Statement
以後,就能夠拿來進行查詢了:
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.<E> handleResultSets(ps);
}
複製代碼