mybatis实现mapper接口的原理,并且绑定对应xml
1.mybatis加载mapper接口和xml的几种方式
1.在mybait配置文件中进行配置文件中进行配置,在mappers标签下配置mapper.xml的文件加载路径,一般都会配置在resource包下
<mappers>
<mapper resource="mapper/xxxMapper.xml"/>
</mappers>
对应的mapper.xml文件都有mapper接口的路径,maybatis通过该路径加载对应的mapper接口
<mapper namespace="org.apache.ibatis.test.mapper.UserMapper">
2.同样在mybait配置文件中进行配置文件中进行配置,在mapper标签下配置对应mapper接口所在包路径,同时对应的xml文件也需要配置在改包下,mybaits通过当前接口找到对应的xml文件
注意,提供maven进行编译的时候不会把在java包下的xml文件加载到classes下,所以需要配置对应加载resources标签)
<mappers>
<package name="org.apache.ibatis.test.mapper"/>
</mappers>
3.通过与spring整合,通过@MapperScan注解扫描对应的mapper进行实现,xml文件需要和机器对应的接口写在同一包下,名称也需要相同
// Springboot启动方式
@SpringBootApplication
@MapperScan({“com.kfit.demo”,“com.kfit.user”})
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
4.整和MybatisPlus,通过配置yml属性的方式进行加载
mybatis-plus:
mapper-locations: # mapper.xml文件路径,例如:classpath:*/mapper/**/*
综上可以得出,mybait配置maperr接口和xml方式可以选择直接配置xml或mapper接口路径来实现,mapper接口方式需要把xml和mapper接口卸载一起
2.mapper接口和xml文件进行绑定流程
1.先解析xml文件,在绑定mapper接口源码流程
1.解析mybaitis-config.xml文件,解析mappers节点(直接配置mybaitis-config.xml文件的时候会进行解析加载)
private void parseConfiguration(XNode root) {
try {
// issue #117 read properties first
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
loadCustomLogImpl(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
mapperElement(root.evalNode("mappers")); // 解析mybatis-config.xml下的mappers标签
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
2.根据mappers标签下的子标签判断是加载xxxMapper.xml文件还是加载mapper接口所在包
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
// 遍历子节点
for (XNode child : parent.getChildren()) {
// 如果是package标签,则则获取name属性,name属性相当于我们配置的mapper接口的包路径,mybaits会加载所有接口和其对应的xml文件放到Configuration属性中去
if ("package".equals(child.getName())) {
String mapperPackage = child.getStringAttribute("name");
// Configuration加载mapper接口
configuration.addMappers(mapperPackage);
} else {
// 解析xml加载方式
String resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
// 直接加载mapper接口方式
String mapperClass = child.getStringAttribute("class");
if (resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
try(InputStream inputStream = Resources.getResourceAsStream(resource)) {
// 通过配置resource路径加载,创建mapperXMl解析器
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
// 解析xml
mapperParser.parse();
}
} else if (resource == null && url != null && mapperClass == null) {
// 通过url方式加载xml
ErrorContext.instance().resource(url);
try(InputStream inputStream = Resources.getUrlAsStream(url)){
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
mapperParser.parse();
}
} else if (resource == null && url == null && mapperClass != null) {
// 加载mapper接口,通过mapper接口找到其对应xml
Class<?> mapperInterface = Resources.classForName(mapperClass);
configuration.addMapper(mapperInterface);
} else {
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
}
}
}
}
3.解析xxxmapper.xml文件
private void configurationElement(XNode context) {
try {
// 对应的mapper接口路径
String namespace = context.getStringAttribute("namespace");
if (namespace == null || namespace.isEmpty()) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
builderAssistant.setCurrentNamespace(namespace);
// 解析缓存相关属性,默认创建本地缓存,缓存机制为lru
cacheRefElement(context.evalNode("cache-ref"));
cacheElement(context.evalNode("cache"));
// 过时
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
// 解析resultmap
resultMapElements(context.evalNodes("/mapper/resultMap"));
// 解析sql片段
sqlElement(context.evalNodes("/mapper/sql"));
// 解析ddl语句,创建MappedStatement放入configurdation中
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
}
}
public void parse() {
if (!configuration.isResourceLoaded(resource)) {
// 解析mapper.xml
configurationElement(parser.evalNode("/mapper"));
configuration.addLoadedResource(resource);
// 加载mapper接口到configuration
bindMapperForNamespace();
}
// 解析一下待处理的数据集合
parsePendingResultMaps();
parsePendingCacheRefs();
parsePendingStatements();
}
private void bindMapperForNamespace() {
// 解析mapper接口所在路径
String namespace = builderAssistant.getCurrentNamespace();
if (namespace != null) {
Class<?> boundType = null;
try {
boundType = Resources.classForName(namespace);
} catch (ClassNotFoundException e) {
// ignore, bound type is not required
}
// configurayion不存在当前mapper接口,把mapper放到configuration中去
if (boundType != null && !configuration.hasMapper(boundType)) {
// Spring may not know the real resource name so we set a flag
// to prevent loading again this resource from the mapper interface
// look at MapperAnnotationBuilder#loadXmlResource
configuration.addLoadedResource("namespace:" + namespace);
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.put(type, new MapperProxyFactory<>(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.
// 解析mapper接口注解,加载xml文件(解析mapper接口上的注解信息)
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
// 解析记载的mapper接口,
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
public void parse() {
// 加载xml文件
String resource = type.toString();
if (!configuration.isResourceLoaded(resource)) {
loadXmlResource();
configuration.addLoadedResource(resource);
assistant.setCurrentNamespace(type.getName());
parseCache();
parseCacheRef();
for (Method method : type.getMethods()) {
if (!canHaveStatement(method)) {
continue;
}
// 解析注解属性
if (getAnnotationWrapper(method, false, Select.class, SelectProvider.class).isPresent()
&& method.getAnnotation(ResultMap.class) == null) {
parseResultMap(method);
}
try {
parseStatement(method);
} catch (IncompleteElementException e) {
configuration.addIncompleteMethod(new MethodResolver(this, method));
}
}
}
// 解析mapper接口中的方法放入configuration
parsePendingMethods();
}
2.先加载mapper接口,在绑定xml文件流程
1.加载mapper接口所在包路径,获取所有的mapper接口
configuration.addMappers(mapperPackage);
public void addMappers(String packageName, Class<?> superType) {
// 解析包路径
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
// 拿到所有当前包路径下的mapper接口
Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
for (Class<?> mapperClass : mapperSet) {
// 加载解析mapper接口
addMapper(mapperClass);
}
}
// 加载mapper接口,同时在加载xml文件
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 {
knownMappers.put(type, new MapperProxyFactory<>(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.
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
流程总结
1.mapper接口会保存在configuration中的mapperRegistry对象中,MapperRegistry有一个MapperProxyFactory的缓存表,mapper接口以MapperProxyFactory代理类的形势进行存储。
public class MapperRegistry {
private final Configuration config;
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();
2.mapper接口中的方法和xml的方法解析以后会存储在configuration的mappedStatements中
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection")
.conflictMessageProducer((savedValue, targetValue) ->
". please check " + savedValue.getResource() + " and " + targetValue.getResource());
xml中的方法不能重复
3.一个简单sql的执行
1.获取mapper接口代理
开启一个会话(mybatis的一般步骤,通常会由spring进行管理)
SqlSession session = sqlSessionFactory.openSession(); // 开启会话
XxxMapper mapper = session.getMapper(XxxMapper.class); // 获取mapper接口
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); // 开启一个新的事务
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();
}
}
2.获取方法增强代理
UserMapper mapper = session.getMapper(UserMapper.class); // 通过接口获取代理对象
// 在MapperRegistry中获取对应的代理类
MapperProxyFactory
@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); // 从knownmappers中获取,相当于代理类工厂缓存对象
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
// 通过代理工厂生成接口实现类 jdk动态代理
T t = mapperProxyFactory.newInstance(sqlSession);
return t;
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
// 代理类生成工厂,
public class MapperProxyFactory<T> {
// 接口对象
private final Class<T> mapperInterface;
// 代理方法实现缓存 mapper接口实现类的方法实现
private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return mapperInterface;
}
public Map<Method, MapperMethodInvoker> getMethodCache() {
return methodCache;
}
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
// jdk动态代理生成实现类,增强方法为mapperProxy的invoke
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
// 生成代理类,传入MapperProxy,MapperProxy实现了InvocationHandler,相当于接口方法增强实现类
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
3.执行sql
调用mapper接口的方法
首先执行InvocationHandler的实现类MapperProxy的invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else {
// 创建调用方法的缓存
return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
创建方法缓存
private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
try {
// 缓存工具类执行
return MapUtil.computeIfAbsent(methodCache, method, m -> {
if (m.isDefault()) {
try {
if (privateLookupInMethod == null) {
return new DefaultMethodInvoker(getMethodHandleJava8(method));
} else {
return new DefaultMethodInvoker(getMethodHandleJava9(method));
}
} catch (IllegalAccessException | InstantiationException | InvocationTargetException
| NoSuchMethodException e) {
throw new RuntimeException(e);
}
} else {
// 创建mappermethod类
return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
}
});
} catch (RuntimeException re) {
Throwable cause = re.getCause();
throw cause == null ? re : cause;
}
}
创建MapperMethod类,创建SqlCommand类
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new SqlCommand(config, mapperInterface, method);
// 方法签名,返回类型,请求参数解析
this.method = new MethodSignature(config, mapperInterface, method);
}
public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
final String methodName = method.getName();
final Class<?> declaringClass = method.getDeclaringClass();
// 获取MappedStatement(从Map<String, MappedStatement> mappedStatements 缓存中获取)
MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
configuration);
if (ms == null) {
if (method.getAnnotation(Flush.class) != null) {
name = null;
type = SqlCommandType.FLUSH;
} else {
throw new BindingException("Invalid bound statement (not found): "
+ mapperInterface.getName() + "." + methodName);
}
} else {
//包装属性
name = ms.getId();
type = ms.getSqlCommandType();
if (type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + name);
}
}
}
public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
// 判断返回类型
if (resolvedReturnType instanceof Class<?>) {
this.returnType = (Class<?>) resolvedReturnType;
} else if (resolvedReturnType instanceof ParameterizedType) {
this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
} else {
this.returnType = method.getReturnType();
}
this.returnsVoid = void.class.equals(this.returnType);
this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
this.returnsCursor = Cursor.class.equals(this.returnType);
this.returnsOptional = Optional.class.equals(this.returnType);
this.mapKey = getMapKey(method);
this.returnsMap = this.mapKey != null;
this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
this.paramNameResolver = new ParamNameResolver(configuration, method);
}
方法执行
MapperMethod的invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
return mapperMethod.execute(sqlSession, args);
}
根据不同的方法类型进行调用
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);
if (method.returnsOptional()
&& (result == null || !method.getReturnType().equals(result.getClass()))) {
result = Optional.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;
}
数据查询
@Override
public <T> T selectOne(String statement, Object parameter) {
// Popular vote was to return null on 0 results and throw exception on too many.
List<T> list = this.selectList(statement, parameter);
if (list.size() == 1) {
return list.get(0);
} else if (list.size() > 1) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return null;
}
}
private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
try {
// 获取 MappedStatement
MappedStatement ms = configuration.getMappedStatement(statement);
// 执行查询
return executor.query(ms, wrapCollection(parameter), rowBounds, handler);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
@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> 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.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
// JDBC执行查询
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
// 封装返回结果
return resultSetHandler.handleResultSets(ps);
}
4.包装返回结果
// 处理resultset jdbc原生返回结果集合
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;
// 结果包装器
ResultSetWrapper rsw = getFirstResultSet(stmt);
// 获取resultmap结果集映射,没有指定会根据返回类自动创建一个
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
// 校验是否存在resultmap
validateResultMapsCount(rsw, resultMapCount);
// 根据resultmap的数量遍历结果
while (rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = resultMaps.get(resultSetCount);
// 处理返回结果集合
handleResultSet(rsw, resultMap, multipleResults, null);
rsw = getNextResultSet(stmt);
// 清空内置结果集和映射
cleanUpAfterHandlingResultSet();
// resultset对应resyktmap处理次数加一
resultSetCount++;
}
// 处理内置结果集合映射
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);
}
// 创建resultset包装器
private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
ResultSet rs = stmt.getResultSet();
while (rs == null) {
// move forward to get the first resultset in case the driver
// doesn't return the resultset as the first result (HSQLDB 2.1)
if (stmt.getMoreResults()) {
rs = stmt.getResultSet();
} else {
if (stmt.getUpdateCount() == -1) {
// no more results. Must be no resultset
break;
}
}
}
return rs != null ? new ResultSetWrapper(rs, configuration) : null;
}
public ResultSetWrapper(ResultSet rs, Configuration configuration) throws SQLException {
super();
// 类型处理器
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.resultSet = rs;
// 原数据集合
final ResultSetMetaData metaData = rs.getMetaData();
final int columnCount = metaData.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
// 数据库字段名称集合
columnNames.add(configuration.isUseColumnLabel() ? metaData.getColumnLabel(i) : metaData.getColumnName(i));
// jdbc类型集合
jdbcTypes.add(JdbcType.forCode(metaData.getColumnType(i)));
// 数据库字段对应的java类型类名称集合
classNames.add(metaData.getColumnClassName(i));
}
}
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) {
// 创建默认结果处理器,内部创建一个list空集合
DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
// 处理结果集每一行数据
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
// 把返回结果放入multipleResults
multipleResults.add(defaultResultHandler.getResultList());
} else {
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
}
} finally {
// issue #228 (close resultsets)
// 关闭ResultSet,数据处理完毕
closeResultSet(rsw.getResultSet());
}
}
// 处理简单结果集映射对象的返回结果
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
throws SQLException {
// 结果集合context,用来传递数据
DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
ResultSet resultSet = rsw.getResultSet();
// 跳过不需要的行数据
skipRows(resultSet, rowBounds);
while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
// 获取每一行的数据
Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
// 存储当前行数据
storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
}
}
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
// 创建结果集对象
Object 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, false)) {
// 单行对象数据,字段名词,数据类型,自动映射(数据不存在别名映射),从jdbc结果集合中根据字段类型和名词把数据填充到对象的对象属性中去
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
}
// 不存在别名映射的属性填充
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
foundValues = lazyLoader.size() > 0 || foundValues;
rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
}
return rowValue;
}
4.与spring的整合使用
1.添加对应的maven依赖
2.在配置类上添加@MapperScan注解。