目录
宏观理解
拿到的 mapper 其实是一个代理对象,底层调用的是 SqlSession 的方法,SqlSession 的方法里其实调用的 Executor 的方法。
源码验证
从 Mapper 到 SqlSession
跟 getMapper:
类 SqlSession
@Override
public <T> T getMapper(Class<T> type) {
return configuration.<T>getMapper(type, this);
}
每一个 SqlSession 都包含一个 Configuration 的引用,所有的配置信息都被解读在里面了。
跟 getMapper:
类 Configuration
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
MapperRegistry
public class MapperRegistry {
private final Configuration config;//config对象,mybatis全局唯一的
//记录了mapper接口与对应MapperProxyFactory之间的关系
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();
public MapperRegistry(Configuration config) {
this.config = config;
}
@SuppressWarnings("unchecked")
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);
}
}
public <T> boolean hasMapper(Class<T> type) {
return knownMappers.containsKey(type);
}
//将mapper接口的工厂类添加到mapper注册中心
//XMLMapperBuilder里的parse()里的bindMapperForNamespace()里的
//configuration.addMapper(boundType)调用
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) {
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
//实例化Mapper接口的代理工程类,并将信息添加至knownMappers
knownMappers.put(type, new MapperProxyFactory<T>(type));
// It's important that the type is added before the parser is run
// otherwise the binding may automatically be attempted by the
// mapper parser. If the type is already known, it won't try.
//解析接口上的注解信息,并添加至configuration对象
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
public Collection<Class<?>> getMappers() {
return Collections.unmodifiableCollection(knownMappers.keySet());
}
public void addMappers(String packageName, Class<?> superType) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
for (Class<?> mapperClass : mapperSet) {
addMapper(mapperClass);
}
}
public void addMappers(String packageName) {
addMappers(packageName, Object.class);
}
}
MapperProxyFactory
public class MapperProxyFactory<T> {
//mapper接口的class对象
private final Class<T> mapperInterface;
//key是mapper接口中的某个方法的method对象,value是对应的MapperMethod,MapperMethod对象不记录任何状态信息,所以它可以在多个代理对象之间共享
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<>();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return mapperInterface;
}
public Map<Method, MapperMethod> getMethodCache() {
return methodCache;
}
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
//创建实现了mapper接口的动态代理对象
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
//每次调用都会创建新的MapperProxy对象,MapperProxy继承了InvocationHandler
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
可以看出来最后是拿到的代理对象。
MapperProxy
学过 JDK 的动态代理就会知道:调用 mapper 接口的方法,其实就是调用这个对象里的 invoke 方法
public class MapperProxy<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
private final SqlSession sqlSession;//记录关联的SqlSession对象
private final Class<T> mapperInterface;//mapper接口对应的class对象;
//key是mapper接口中的某个方法的method对象,value是对应的MapperMethod,MapperMethod对象不记录任何状态信息,所以它可以在多个代理对象之间共享
private final Map<Method, MapperMethod> methodCache;
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {//如果是Object本身的方法不增强
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
//从缓存中获取mapperMethod对象,如果缓存中没有,则创建一个,并添加到缓存中
final MapperMethod mapperMethod = cachedMapperMethod(method);
//调用execute方法执行sql,可以看出并没有执行method.invoke
return mapperMethod.execute(sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
return methodCache.computeIfAbsent(method, k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
}
@UsesJava7
private Object invokeDefaultMethod(Object proxy, Method method, Object[] args)
throws Throwable {
final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class
.getDeclaredConstructor(Class.class, int.class);
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
final Class<?> declaringClass = method.getDeclaringClass();
return constructor
.newInstance(declaringClass,
MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
| MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC)
.unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
}
/**
* Backport of java.lang.reflect.Method#isDefault()
*/
private boolean isDefaultMethod(Method method) {
return (method.getModifiers()
& (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC
&& method.getDeclaringClass().isInterface();
}
}
MapperMethod
封装了 mapper 接口中对应方法的信息,以及对应的 sql 语句的信息
它是 mapper 接口与映射配置文件中 sql 语句的桥梁
MapperMethod 对象不记录任何状态信息,所以它可以在多个代理对象之间共享
它有3个内部类:
- SqlCommand : 从 configuration 中获取方法的命名空间.方法名以及 sql 语句的类型
- MethodSignature:封装 mapper 接口方法的相关信息(入参,返回类型)
- ParamNameResolver: 解析 mapper 接口方法中的入参,将多个参数转成 Map
public class MapperMethod {
//从configuration中获取方法的命名空间.方法名以及SQL语句的类型(SELECT等)
private final SqlCommand command;
//封装mapper接口方法的相关信息(入参,返回类型)
private final MethodSignature method;
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new SqlCommand(config, mapperInterface, method);
this.method = new MethodSignature(config, mapperInterface, method);
}
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
//根据sql语句类型以及接口返回的参数选择调用不同的
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()) {//返回值为void
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {//返回值为集合或者数组
//这个方法里面其实就是调用的SqlSession的方法
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {//返回值为map
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {//返回值为游标
result = executeForCursor(sqlSession, args);
} else {//处理返回为单一对象的情况
//通过参数解析器解析解析参数
Object param = method.convertArgsToSqlCommandParam(args);
//调用SqlSession的方法,重点看
result = sqlSession.selectOne(command.getName(), param);
if (method.returnsOptional() &&
(result == null || !method.getReturnType().equals(result.getClass()))) {
result = OptionalUtil.ofNullable(result);
}
}
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;
}
//省略了大部分方法
}
从 SqlSession 到 Executor
之前的代码已经看到,当返回对象为单一对象的情况,调用的是 selectOne 方法
但最终,会调用到 selectList 方法:
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
//从configuration中获取要执行的sql语句的配置信息
MappedStatement ms = configuration.getMappedStatement(statement);
//通过executor执行语句,并返回指定的结果集
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();
}
}
跟 query:
类 Executor
会调哪个方法呢?
SqlSession sqlSession = sqlSessionFactory.openSession();
这是我们获取 sqlSession 的代码
跟 openSession:
类 DefaultSqlSessionFactory:
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
跟 openSessionFromDataSource:
//从数据源获取数据库连接
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//获取mybatis配置文件中的environment对象
final Environment environment = configuration.getEnvironment();
//从environment获取transactionFactory对象
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//创建事务对象
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//根据配置创建executor
final Executor executor = configuration.newExecutor(tx, execType);
//创建DefaultSqlSession
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();
}
}
跟 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);
}
//如果有<setting name="cacheEnabled" value="true" />节点,
//通过装饰器,添加二级缓存的能力
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
//通过interceptorChain遍历所有的插件为executor增强,添加插件的功能
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
看见没有,装饰器模式,会给你的 executor,套上 CachingExecutor。
而 cacheEnabled 在 Configuration 里默认是 true 的。
而有了这些,并不是真的开启了二级缓存。要开启二级缓存,得在 Mapper.xml 文件里加上 <cache> 相关标签,这个会在 Mybatis 初始化时,被 XMLMapperBuilder 解析到,交给 builderAssistant 创建 Cache 并存储到 Configuration 的一个 Map里,以 namespace 为 key。
详情请看 Mybatis 的初始化与建造者模式
CachingExecutor
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//获取sql语句信息,占位符,参数等信息
BoundSql boundSql = ms.getBoundSql(parameterObject);
//拼装缓存的key值
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
//从MappedStatement中获取二级缓存
Cache cache = ms.getCache();
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);//从二级缓存中获取数据
if (list == null) {
//二级缓存为空,才会调用BaseExecutor.query
list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
开启了二级缓存,而没有,或者没开启二级缓存,都会执行 delegate.<E> query
BaseExecutor
@Override
public <E> List<E> 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) {//检查当前executor是否关闭
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {//非嵌套查询,并且FlushCache配置为true,则需要清空一级缓存
clearLocalCache();
}
List<E> list;
try {
queryStack++;//查询层次加一
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);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {//延迟加载处理
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {//如果当前sql的一级缓存配置为STATEMENT,查询完既清空一集缓存
// issue #482
clearLocalCache();
}
}
return list;
}
//真正访问数据库获取结果的方法
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
localCache.putObject(key, EXECUTION_PLACEHOLDER);//在缓存中添加占位符
try {
//调用抽象方法doQuery,方法查询数据库并返回结果,可选的实现包括:simple、reuse、batch
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;
}
跟 doQuery:
可以看出,这是一个模板方法,模板模式的体现。默认的是 SimpleExecutor 实现。
BaseExecutor 定义了一套骨架流程:
红色的部分就是不同的 doQuery 实现。
SimpleExecutor
@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();//获取configuration对象
//创建StatementHandler对象,
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
//StatementHandler对象创建stmt,并使用parameterHandler对占位符进行处理
stmt = prepareStatement(handler, ms.getStatementLog());
//通过statementHandler对象调用ResultSetHandler将结果集转化为指定对象返回
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
doQuery 里的 newStatementHandler
先跟 newStatementHandler:
类 Configuration
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//创建RoutingStatementHandler对象,实际由statmentType来指定真实的StatementHandler来实现
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
StatementHandler
创建了一个 StatementHandler 的引用,对象是 RoutingStatementHandler:
跟 RoutingStatementHandler:
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//RoutingStatementHandler最主要的功能就是根据mappedStatment的配置,生成一个对应的StatementHandler对象并赋值给delegate
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());
}
}
可以看出来这是个静态代理,根据配置选择代理对象。默认是 PREPARED,也就是预编译的。
doQuery 里的 prepareStatement
回去跟 prepareStatement:
//创建Statement
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
//获取connection对象的动态代理,添加日志能力;
Connection connection = getConnection(statementLog);
//通过不同的StatementHandler,利用connection创建(prepare)Statement
stmt = handler.prepare(connection, transaction.getTimeout());
//使用parameterHandler处理占位符
handler.parameterize(stmt);
return stmt;
}
跟 prepare:
类 StatementHandler
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
return delegate.prepare(connection, transactionTimeout);
}
由前面可以知道,这个 delegate 是 PreparedStatementHandler。但由于这个方法它并没有重写,所以还是得看它的父类 BaseStatementHandler
@Override
//使用模板模式,定义了获取Statement的步骤,其子类实现实例化Statement的具体的方式;
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
//通过不同的子类实例化不同的Statement,分为三类:simple(statment)、prepare(prepareStatement)、callable(CallableStatementHandler)
statement = instantiateStatement(connection);
//设置超时时间
setStatementTimeout(statement, transactionTimeout);
//设置数据集大小
setFetchSize(statement);
return statement;
} catch (SQLException e) {
closeStatement(statement);
throw e;
} catch (Exception e) {
closeStatement(statement);
throw new ExecutorException("Error preparing statement. Cause: " + e, e);
}
}
跟 instantiateStatement:
这就是一个需要子类重写的骨架方法了
@Override
//使用底层的prepareStatement对象来完成对数据库的操作
protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = boundSql.getSql();
//根据mappedStatement.getKeyGenerator字段,创建prepareStatement
if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {//对于insert语句
String[] keyColumnNames = mappedStatement.getKeyColumns();
if (keyColumnNames == null) {
//返回数据库生成的主键
return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
} else {
//返回数据库生成的主键填充至keyColumnNames中指定的列
return connection.prepareStatement(sql, keyColumnNames);
}
} else if (mappedStatement.getResultSetType() != null) {
//设置结果集是否可以滚动以及其游标是否可以上下移动,设置结果集是否可更新
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
} else {
//创建PrepareStatement对象,这是熟悉的JDBC代码里了
return connection.prepareStatement(sql);
}
}
//回去看前面最近一条分界线下面的方法,紧接着prepareStatement就是下面这个方法了
@Override
//使用parameterHandler对sql语句的占位符进行处理
public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}
跟 setParameters:
ParameterHandler
对 sql 语句的占位符进行处理
public interface ParameterHandler {
Object getParameterObject();
void setParameters(PreparedStatement ps)
throws SQLException;
}
public class DefaultParameterHandler implements ParameterHandler {
//typeHandler注册中心
private final TypeHandlerRegistry typeHandlerRegistry;
//对应的sql节点的信息
private final MappedStatement mappedStatement;
//用户传入的参数
private final Object parameterObject;
//SQL语句信息,其中还包括占位符和参数名称信息
private final BoundSql boundSql;
private final Configuration configuration;
public DefaultParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
this.mappedStatement = mappedStatement;
this.configuration = mappedStatement.getConfiguration();
this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
this.parameterObject = parameterObject;
this.boundSql = boundSql;
}
@Override
public Object getParameterObject() {
return parameterObject;
}
@Override
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
//从boundSql中获取sql语句的占位符对应的参数信息
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
//遍历这个参数列表,把参数设置到PreparedStatement中
if (parameterMappings != null) {
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {//对于存储过程中的参数不处理
Object value;//绑定的实参
String propertyName = parameterMapping.getProperty();//参数的名字
if (boundSql.hasAdditionalParameter(propertyName)) { // 获取对应的实参值
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
TypeHandler typeHandler = parameterMapping.getTypeHandler();//从parameterMapping中获取typeHandler对象
JdbcType jdbcType = parameterMapping.getJdbcType();//获取参数对应的jdbcType
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
//为statment中的占位符绑定参数
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
} catch (SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}
}
doQuery 里的 query
类 PreparedStatementHandler
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
//JDBC方法
ps.execute();
return resultSetHandler.<E> handleResultSets(ps);
}
ResultSetHandler
找到映射匹配规则、反射实例化目标对象、根据规则填充属性值
public interface ResultSetHandler {
<E> List<E> handleResultSets(Statement stmt) throws SQLException;
<E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
void handleOutputParameters(CallableStatement cs) throws SQLException;
}
类 DefaultResultSetHandler
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
//用于保存结果集对象
final List<Object> multipleResults = new ArrayList<>();
int resultSetCount = 0;
//statment可能返回多个结果集对象,这里先取出第一个结果集
ResultSetWrapper rsw = getFirstResultSet(stmt);
//获取结果集对应resultMap,本质就是获取字段与java属性的映射规则
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);//结果集和resultMap不能为空,为空抛出异常
while (rsw != null && resultMapCount > resultSetCount) {
//获取当前结果集对应的resultMap
ResultMap resultMap = resultMaps.get(resultSetCount);
//根据映射规则(resultMap)对结果集进行转化,转换成目标对象以后放入multipleResults中
handleResultSet(rsw, resultMap, multipleResults, null);
rsw = getNextResultSet(stmt);//获取下一个结果集
cleanUpAfterHandlingResultSet();//清空nestedResultObjects对象
resultSetCount++;
}
//获取多结果集。多结果集一般出现在存储过程的执行,存储过程返回多个resultset,
//mappedStatement.resultSets属性列出多个结果集的名称,用逗号分割;
//多结果集的处理不是重点
String[] resultSets = mappedStatement.getResultSets();
if (resultSets != null) {
while (rsw != null && resultSetCount < resultSets.length) {
ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
if (parentMapping != null) {
String nestedResultMapId = parentMapping.getNestedResultMapId();
ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
handleResultSet(rsw, resultMap, null, parentMapping);
}
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
}
return collapseSingleResultList(multipleResults);
}
跟 handleResultSet:
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
try {
if (parentMapping != null) {//处理多结果集的嵌套映射
handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
} else {
if (resultHandler == null) {//如果resultHandler为空,实例化一个人默认的resultHandler
DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
//对ResultSet进行映射,映射结果暂存在resultHandler中
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
//将暂存在resultHandler中的映射结果,填充到multipleResults
multipleResults.add(defaultResultHandler.getResultList());
} else {
//使用指定的rusultHandler进行转换
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
}
} finally {
// issue #228 (close resultsets)
//调用resultset.close()关闭结果集
closeResultSet(rsw.getResultSet());
}
}
跟 handleRowValues:
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
if (resultMap.hasNestedResultMaps()) {//处理有嵌套resultmap的情况
ensureNoRowBounds();
checkResultHandler();
handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
} else {//处理没有嵌套resultmap的情况
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
跟 handleRowValuesForSimpleResultMap:
//简单映射处理
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
throws SQLException {
//创建结果上下文,所谓的上下文就是专门在循环中缓存结果对象的
DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
//1.根据分页信息,定位到指定的记录
skipRows(rsw.getResultSet(), rowBounds);
//2.shouldProcessMoreRows判断是否需要映射后续的结果,实际还是翻页处理,避免超过limit
while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
//3.进一步完善resultMap信息,主要是处理鉴别器的信息
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
//4.读取resultSet中的一行记录并进行映射,转化并返回目标对象
Object rowValue = getRowValue(rsw, discriminatedResultMap);
//5.保存映射结果对象
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}