1初步:
MyBatis初始化完后,org.apache.ibatis.session.Configuration
中,会有已经初始化完的数据,供后续的执行:
1.1 mapperRegistry
MapperRegistry
的实例,有一个属性Map<Class<?>, MapperProxyFactory<?>> knownMappers
:
- 密钥:Mapper类,某种接口'com.xxx.yyy.model.UserMapper';
- 值:
MapperProxyFactory
对象,是Mapper代理类MapperProxy
的工厂,创建MapperProxy
对象执行Mapper类中定义的方法。
1.2 mappingStatement
类型是Map<String, MappedStatement>
:
- key:
MappedStatement
对象的id,如'com.xxx.yyy.model.UserMapper.selectList'; - 值:
MappedStatement
对象。
2查询过程
MyBatis分三个步骤执行查询过程:
- 1创建SqlSession,默认实现类是
DefaultSqlSession
; - 1获取Mapper,如
session.getMapper(UserMapper.class)
; - 2用Mapper执行查询,如
userMapper.findList()
。
2.1创建SqlSession
DefaultSqlSessionFactory.openSession
:
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);
复制代码
执行者从Configuration.newExecutor
方法中创建:
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
的执行过程如下:
- 根据不同的ExecutorType返回不同Executor;
- 因配置中默认为ExecutorType.SIMPLE,所以默认使用
SimpleExecutor
; - 如果开启了缓存,则返回
CachingExecutor
对象; - 通过
interceptorChain.pluginAll
加入拦截器Interceptor
列表。
2.2获取映射器
DefaultSqlSession
从Configuration.mapperRegistry
中映射电子杂志的实现对象:
// 第一步
// 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
。
2.3执行查询
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);
复制代码
2.3.1 MapperMethod创建
MapperMethod
有两个属性:
private final SqlCommand command;
private final MethodSignature method;
复制代码
1)SqlCommand
SqlCommand
有两个属性:
- 字符串名称:MappedStatement的id;
- SqlCommandType类型:MappedStatement的sqlCommandType,UNKNOWN,INSERT,UPDATE,DELETE,SELECT,FLUSH。
SqlCommand创建时,会从配置中获取MappedStatement对象,获取到应使用的名称和类型的赋值:
String statementId = mapperInterface.getName() + "." + methodName;
if (configuration.hasStatement(statementId)) {
return configuration.getMappedStatement(statementId);
}
复制代码
2)方法签名
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)
复制代码
2.3.2 MapperMethod.execute
根据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;
}
复制代码
在执行调用的
executeFor*
方法中,最终调用的是sqlSession.select*
方法。
2.3.3 session.selectList
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);
}
}
复制代码
2.3.4 StatementHandler
1)RoutingStatementHandler
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());
}
}
复制代码
2)StatementHandler.prepare
创建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();
}
}
复制代码
3)StatementHandler.query
有了Statement
之后,就可以拿来进行查询了:
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.<E> handleResultSets(ps);
}