获取 SqlSession
mapper 解析完毕后,整个 configuration 就算解析完成,根据 sqlSessionFactory 获取 session,然后获取 mapper 执行 sql
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
openSession() 方法调用重载方法
//DefaultSqlSessionFactory
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
// JdbcTransactionFactory
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
// JdbcTransaction
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
// CachingExecutor、
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();
}
}
返回创建 DefaultSqlSession
获取 Mapper
BlogDao blogDao = sqlSession.getMapper(BlogDao.class);
从已解析的结果集合中取出对应的 MapperProxyFactory,创建相应的代理
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 代理类,代码如下
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
MapperProxy 实现了 InvocationHandler 接口,也就是说获取的 Mapper 对象方法调用最后会调用 MapperProxy.invoke()
执行 SQL
调用 MapperProxy.invoke() 方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
如果是 Object 类的方法或者 default 方法直接执行,其它方法 执行 mapperMethod.execute(),execute 方法根据类型执行相应的语句
- INSERT -> sqlSession.insert
- UPDATE -> sqlSession.update
- DELETE-> sqlSession.delete
- SELECT-> sqlSession.select*
- FLUSH-> sqlSession.flushStatements
select 方法 有多种,需要进行结果集映射,以 executeForMany(sqlSession, args) 为例来看,方法会调用 sqlSession.selectList()
// DefaultSqlSession.selectList
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
}
// CachingExecutor.query
public <E> List<E> 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);
}
boundSql 中包含之中要执行的 sql,getBoundSql 方法会通过 SqlSource 来获取 ,这里的 sqlSource 为之前解析的,存在两种:DynamicSqlSource,RawSqlSource。
- RawSqlSource 相比 DynamicSqlSource 就简单多了,在创建 RawSqlSource 时直接就将 sql 解析了,直接获取即可。
- 动态 sql 会在执行时解析并转化为静态 sql
调用 query 方法,这里调用的虽然是 CachingExecutor 类,但最后会委派给 SimpleExecutor 调用,调用会访问 cache,并把结果放在 cache 中
@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);
}
}
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
String sql = boundSql.getSql();
statement.execute(sql);
return resultSetHandler.<E>handleResultSets(statement);
}
结果映射
在处理结果集行值时分为两部分,处理简单 resultMap 对应的行值和处理嵌套 resultMap 对应的行值,是否嵌套映射在解析 mapper resultMap 的时候已经解释过了,这里不再重复。处理简单 resultMap 对应的行值稍微简单些,先看简单的映射
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
throws SQLException {
DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
//处理分页,跳过指定的行,如果rs类型不是TYPE_FORWARD_ONLY,直接absolute,否则的话循环rs.next
skipRows(rsw.getResultSet(), rowBounds);
while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
//处理行值,重点分析
Object rowValue = getRowValue(rsw, discriminatedResultMap);
//保存对象,通过list保存生成的对象Object
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null);
if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
final MetaObject metaObject = configuration.newMetaObject(rowValue);
boolean foundValues = this.useConstructorMappings;
if (shouldApplyAutomaticMappings(resultMap, false)) {
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
}
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
foundValues = lazyLoader.size() > 0 || foundValues;
rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
}
return rowValue;
}
获取行值主要包含如下 3 个步骤:
-
createResultObject() 方法创建结果集对象
根据 resultType,通过 ObjectFactory.create 来创建对象,其实现原理还是通过反射来创建对象。在创建对象时如果 resultMap 未配置 constructor,通过默认构造方法来创建对象,否则通过有参的构造方法来创建对象 -
自动映射属性
applyAutomaticMappings(),如果 ResultMap 配置了 autoMapping=“true”,或者 AutoMappingBehavior 为 PARTIAL 会自动映射在 resultSet 查询列中存在但是未在 resultMap 中配置的列。 -
人工映射属性
映射在 resultMap 中配置的列,主要包括两步:获取属性的值和设置属性的值。//获取属性的值 Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix); //设置属性的值,通过反射来设置 metaObject.setValue(property, value);
private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException { //获取嵌套查询对应的属性值,最终还是通过Executor.query来获取属性值 if (propertyMapping.getNestedQueryId() != null) { return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix); } else if (propertyMapping.getResultSet() != null) { addPendingChildRelation(rs, metaResultObject, propertyMapping); // TODO is that OK? return DEFERED; } else { final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler(); final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix); //通过typeHandler来获取属性的值,如StringTypeHandler获取属性值:rs.getString(columnName) return typeHandler.getResult(rs, column); } }
嵌套映射
嵌套 resultMap 主要用来处理 collection,association 属性
<resultMap id="detailedBlogResultMap" type="Blog">
<result property="id" column="id"/>
<result property="title" column="title"/>
<result property="content" column="content"/>
<association property="author" javaType="com.zero.mybatis.bean.Author">
<id property="id" column="author"/>
<id property="name" column="name"/>
<id property="age" column="age"/>
</association>
</resultMap>
<!--alias Blog-->
<select id="selectBlog" resultMap="detailedBlogResultMap">
select * from blog join author on blog.author = author.id where blog.id = 1;
</select>
Blog 有一个 author 属性,代表 Author 的 id
处理嵌套映射主要包括如下几个步骤:
- skipRows(rsw.getResultSet(), rowBounds); 同简单映射
- createRowKey,根据 resultMap 下的列创建 rowKey,很有用。在如上 liveCourseMap 配置中,mybatis 将会根据 id 列和 course_name 列的值来创建 rowKey
- getRowValue
在 handleRowValues() 方法中,if 条件成立进入 handleRowValuesForNestedResultMap() 方法
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
if (resultMap.hasNestedResultMaps()) {
ensureNoRowBounds();
checkResultHandler();
handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
} else {
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
final DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
skipRows(rsw.getResultSet(), rowBounds);
Object rowValue = previousRowValue;
while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
//创建rowKey,根据rowKey判断对象创建没创建
final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);
//已经创建的对象会保存到nestedResultObjects
Object partialObject = nestedResultObjects.get(rowKey);
// issue #577 && #542
if (mappedStatement.isResultOrdered()) {
if (partialObject == null && rowValue != null) {
nestedResultObjects.clear();
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
} else {
rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
if (partialObject == null) {
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
}
if (rowValue != null && mappedStatement.isResultOrdered() && shouldProcessMoreRows(resultContext, rowBounds)) {
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
previousRowValue = null;
} else if (rowValue != null) {
previousRowValue = rowValue;
}
}
getRowValue() 方法
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, String columnPrefix, Object partialObject) throws SQLException {
final String resultMapId = resultMap.getId();
Object rowValue = partialObject;
if (rowValue != null) {
final MetaObject metaObject = configuration.newMetaObject(rowValue);
putAncestor(rowValue, resultMapId);
applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);
ancestorObjects.remove(resultMapId);
} else {
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
// 创建外部对象
rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
final MetaObject metaObject = configuration.newMetaObject(rowValue);
boolean foundValues = this.useConstructorMappings;
if (shouldApplyAutomaticMappings(resultMap, true)) {
//自动映射
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
}
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
putAncestor(rowValue, resultMapId);
//嵌套映射
foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;
ancestorObjects.remove(resultMapId);
foundValues = lazyLoader.size() > 0 || foundValues;
rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
}
if (combinedKey != CacheKey.NULL_CACHE_KEY) {
nestedResultObjects.put(combinedKey, rowValue);
}
}
return rowValue;
}