MyBatis源码学习
背景
执行一个Sql查询MyBatis做了什么操作?
//1SqlSessionFactory 创建sqlsession SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //2 这里打开openSession SqlSession sqlSession = sqlSessionFactory.openSession(); //3 getMapper 创建一个 代理对象MapperRegistry.mapperProxyFactory.newInstance(sqlSession); UserMapper mapper = sqlSession.getMapper(UserMapper.class); //4 执行查询 User user = mapper.selectUser(1L);
1.MyBatis执行过程
MyBatis3.5.2源码
1.SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try { //读取xml 生成一个document //通过xpath获取节点内容 XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); //parser.parse() 通过xpath读取document 生成configuration,并且将 //mapper.java 类和mapper.xml 进行映射并且存放如 hashmap 里面 //通过解析mapper.xml里面的sql 每个mapper.java 里面的方法生成一个MapperStatement return build(parser.parse()); } catch (Exception e) { } }
1.解析xml生成configuration
解析xml文件中的入参和返参生成实体类,存放到map里面,生成MapperStatement,解析xml生成SqlSource,将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")); //扫描所有的mapper文件添加到hashmap 里面 //读取配置文件里面mapper.xml的配置 //调用 mapperRegistry.addMapper(type); mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } }
1.1生成MapperStatement
private void mapperElement(XNode parent) throws Exception { if (parent != null) { for (XNode child : parent.getChildren()) { if ("package".equals(child.getName())) { String mapperPackage = child.getStringAttribute("name"); configuration.addMappers(mapperPackage); } else { String resource = child.getStringAttribute("resource"); String url = child.getStringAttribute("url"); String mapperClass = child.getStringAttribute("class"); if (resource != null && url == null && mapperClass == null) { ErrorContext.instance().resource(resource); InputStream inputStream = Resources.getResourceAsStream(resource); XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments()); //XMLMapperBuilder.parse.configurationElement mapperParser.parse(); } else if (resource == null && url != null && mapperClass == null) { ErrorContext.instance().resource(url); InputStream inputStream = Resources.getUrlAsStream(url); XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments()); mapperParser.parse(); } else if (resource == null && url == null && mapperClass != null) { 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."); } } } } }
1.2
mapperParser.parse()-configurationElement; private void configurationElement(XNode context) { try { String namespace = context.getStringAttribute("namespace"); if (namespace == null || namespace.equals("")) { throw new BuilderException("Mapper's namespace cannot be empty"); } builderAssistant.setCurrentNamespace(namespace); cacheRefElement(context.evalNode("cache-ref")); cacheElement(context.evalNode("cache")); //解析 生成一个 ParameterMap 并且添加到configuration的 ParameterMap里面 parameterMapElement(context.evalNodes("/mapper/parameterMap")); //解析 生成一个 ResultMap 并且添加到configuration的 ResultMap 里面 //这里已经生成 ResultMap 是根据xml里面的 xml转换为实体类 resultMapElements(context.evalNodes("/mapper/resultMap")); //这里是解析sql 片段 如: <sql id="Example_Where_Clause"> sqlElement(context.evalNodes("/mapper/sql")); //解析 生成一个MapperStatement 包含SqlSource 添加到configuration的mappedStatements // 解析SQL生成SqlBound ?不是这里完成的 //这里是解析 具体的<select> parseStatementNode.addMappedStatement 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); } }
1.3 解析Mapper.xml中如parameterMap
private void parameterMapElement(List<XNode> list) { for (XNode parameterMapNode : list) { String id = parameterMapNode.getStringAttribute("id"); String type = parameterMapNode.getStringAttribute("type"); Class<?> parameterClass = resolveClass(type); List<XNode> parameterNodes = parameterMapNode.evalNodes("parameter"); List<ParameterMapping> parameterMappings = new ArrayList<>(); for (XNode parameterNode : parameterNodes) { String property = parameterNode.getStringAttribute("property"); String javaType = parameterNode.getStringAttribute("javaType"); String jdbcType = parameterNode.getStringAttribute("jdbcType"); String resultMap = parameterNode.getStringAttribute("resultMap"); String mode = parameterNode.getStringAttribute("mode"); String typeHandler = parameterNode.getStringAttribute("typeHandler"); Integer numericScale = parameterNode.getIntAttribute("numericScale"); ParameterMode modeEnum = resolveParameterMode(mode); Class<?> javaTypeClass = resolveClass(javaType); JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType); Class<? extends TypeHandler<?>> typeHandlerClass = resolveClass(typeHandler); ParameterMapping parameterMapping = builderAssistant.buildParameterMapping(parameterClass, property, javaTypeClass, jdbcTypeEnum, resultMap, modeEnum, typeHandlerClass, numericScale); parameterMappings.add(parameterMapping); } builderAssistant.addParameterMap(id, parameterClass, parameterMappings); } }
1.4 解析xml文件中的<resultMap/>:XMLMapperBuilder.resultMapElement
private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings, Class<?> enclosingType) throws Exception { ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier()); String type = resultMapNode.getStringAttribute("type", resultMapNode.getStringAttribute("ofType", resultMapNode.getStringAttribute("resultType", resultMapNode.getStringAttribute("javaType")))); Class<?> typeClass = resolveClass(type); if (typeClass == null) { typeClass = inheritEnclosingType(resultMapNode, enclosingType); } Discriminator discriminator = null; List<ResultMapping> resultMappings = new ArrayList<>(); resultMappings.addAll(additionalResultMappings); List<XNode> resultChildren = resultMapNode.getChildren(); for (XNode resultChild : resultChildren) { // <constructor></constructor> 这个类型的映射 if ("constructor".equals(resultChild.getName())) { processConstructorElement(resultChild, typeClass, resultMappings); } else if ("discriminator".equals(resultChild.getName())) { discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings); } else { List<ResultFlag> flags = new ArrayList<>(); if ("id".equals(resultChild.getName())) { flags.add(ResultFlag.ID); } resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags)); } } String id = resultMapNode.getStringAttribute("id", resultMapNode.getValueBasedIdentifier()); String extend = resultMapNode.getStringAttribute("extends"); Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping"); ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping); try { //添加到configuration里面的resultMap return resultMapResolver.resolve(); } catch (IncompleteElementException e) { configuration.addIncompleteResultMap(resultMapResolver); throw e; } }
1.5 解析xml文件中的Insert,Select,Update ,delete 标签生成MapperStatement
MapperRegistry.addMapper 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. /** * 添加注解类的 如在mapper.java 类里面添加如 * @ResultMap("com.fyp.demo.dao.UserMapper.BaseResultMap") * @Select("select * from user where name=#{name}") */ MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type); /** * 生成MapperStatement MapperAnnotationBuilder .parse(parseStatement) 生成 MapperAnnotationBuilder.parseStatementSqlSource 通过getSqlSourceFromAnnotations */ parser.parse(); loadCompleted = true; } finally { if (!loadCompleted) { knownMappers.remove(type); } } } }
1.5.1MapperStatement创建
XMLStatementBuilder:parseStatementNode public void parseStatementNode() { String id = context.getStringAttribute("id"); String databaseId = context.getStringAttribute("databaseId"); if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) { return; } String nodeName = context.getNode().getNodeName(); SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH)); boolean isSelect = sqlCommandType == SqlCommandType.SELECT; boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect); boolean useCache = context.getBooleanAttribute("useCache", isSelect); boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false); // Include Fragments before parsing XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant); includeParser.applyIncludes(context.getNode()); String parameterType = context.getStringAttribute("parameterType"); Class<?> parameterTypeClass = resolveClass(parameterType); String lang = context.getStringAttribute("lang"); LanguageDriver langDriver = getLanguageDriver(lang); // Parse selectKey after includes and remove them. processSelectKeyNodes(id, parameterTypeClass, langDriver); // Parse the SQL (pre: <selectKey> and <include> were parsed and removed) KeyGenerator keyGenerator; String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX; keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true); if (configuration.hasKeyGenerator(keyStatementId)) { keyGenerator = configuration.getKeyGenerator(keyStatementId); } else { keyGenerator = context.getBooleanAttribute("useGeneratedKeys", configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType)) ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE; } //XMLLanguageDriver 将#{}的语句替换为? SqlSourceBuilder.parse SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass); //select * from user where id = ? StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString())); Integer fetchSize = context.getIntAttribute("fetchSize"); Integer timeout = context.getIntAttribute("timeout"); String parameterMap = context.getStringAttribute("parameterMap"); String resultType = context.getStringAttribute("resultType"); Class<?> resultTypeClass = resolveClass(resultType); String resultMap = context.getStringAttribute("resultMap"); String resultSetType = context.getStringAttribute("resultSetType"); ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType); if (resultSetTypeEnum == null) { resultSetTypeEnum = configuration.getDefaultResultSetType(); } String keyProperty = context.getStringAttribute("keyProperty"); String keyColumn = context.getStringAttribute("keyColumn"); String resultSets = context.getStringAttribute("resultSets"); //MappedStatement builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets); }
1.6 创建MapperStatement时候解析Sql,SqlSource sqlSource = langDriver.createSqlSource(解析sql替换为?
XMLLanguageDriver:parseScriptNode
XMLScriptBuilder:parseScriptNode具体的sql替换和解析
public SqlSource parseScriptNode() { MixedSqlNode rootSqlNode = parseDynamicTags(context); SqlSource sqlSource; if (isDynamic) { sqlSource = new DynamicSqlSource(configuration, rootSqlNode); } else { sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType); } return sqlSource; } SqlSourceBuilder:parse public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) { ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters); GenericTokenParser parser = new GenericTokenParser("#{", "}", handler); String sql = parser.parse(originalSql); return new StaticSqlSource(configuration, sql, handler.getParameterMappings()); }
2.创建DefaultSqlSessionFactory
2.1创建SqlSession
public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); }
2.2
DefaultSqlSessionFactory.openSession(openSessionFromDataSource) 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); //构建executor SimpleExecutor final Executor executor = configuration.newExecutor(tx, execType); log.info("configurantion={}", configuration); 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.3
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 = (Executor) interceptorChain.pluginAll(executor); return executor; }
3. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
MapperRegistry.getMapper @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); } } MapperProxyFactory.newInstance protected T newInstance(MapperProxy<T> mapperProxy) { //MapperProxy . invoke 方法 这里是创建了 mapper.java 的接口对应的 实现类通过代理 创建一个代理类 return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); } public T newInstance(SqlSession sqlSession) { final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); }
4.User user = mapper.selectUser(1L);
4.1 调用代理对象执行sql
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { //如果是Object的方法 直接执行 if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } else if (method.isDefault()) { // return invokeDefaultMethod(proxy, method, args); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } // /** * 缓存执行方法 方法名为key,缓存的是原始方法加上 原始SQL * selectTeacher value=select * from teacher where id = ? */ //公共方法名和类名获取执行的MapperStatement final MapperMethod mapperMethod = cachedMapperMethod(method); return mapperMethod.execute(sqlSession, args); }
public Object execute(SqlSession sqlSession, Object[] args) { //通过 MapperProxy 的invoke 方法 最后调用这里的execute //填充入参 ?替换为具体的值 //ParamNameResolver 参数替换 //如何判断是返回list 还是单条? //1根据Sql类型(insert.delete ,update select // 如果是select 再根据方法返回值判断返回结果类型 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 { //解析入参 ParamNameResolver .getNamedParams 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 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; } } @Override public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { try { //statement=com.fyp.demo.dao.UserMapper.selectUser MappedStatement ms = configuration.getMappedStatement(statement); //BaseExecutor.query(queryFromDatabase) 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(); } } // BaseExecutor.queryFromDatabase 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 { 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; }
SimpleExecutor.doQuery @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 根据RoutingStatementHandler 创建具体的Statement 如调用存储过程的 批量的等 //PreparedStatementHandler 在BaseStatementHandler 里面创建ResultHandler 和ParamenterHandler StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); // 初始化Sql将?替换为具体的值 SimpleExecutor.prepareStatement stmt = prepareStatement(handler, ms.getStatementLog()); // PreparedStatementHandler return handler.query(stmt, resultHandler); } finally { //关闭 statement closeStatement(stmt); } } configuration.newStatementHandler(RoutingStatementHandler) public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { switch (ms.getStatementType()) { case STATEMENT: //SimpleStatementHandler 在构造函数里面创建了 parameterHandler和resultHandler delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; case PREPARED: //BaseStatementHandler(创建parameterHandler,resultSetHandler) 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()); } } SimpleExecutor.prepareStatement private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; Connection connection = getConnection(statementLog); //设置statement属性 stmt = handler.prepare(connection, transaction.getTimeout()); //参数化 ?号处理为具体的参数 DefaultParameterHandler.setParameters handler.parameterize(stmt); return stmt; } BaseStatementHandler.prepare 创建statement @Override public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException { ErrorContext.instance().sql(boundSql.getSql()); Statement statement = null; try { 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); } } DefaultParameterHandler.setParameters @Override public void setParameters(PreparedStatement ps) { ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); 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)) { // issue #448 ask first for additional params 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(); JdbcType jdbcType = parameterMapping.getJdbcType(); if (value == null && jdbcType == null) { jdbcType = configuration.getJdbcTypeForNull(); } try { //设置参数 将?号填充为具体的参数 typeHandler.setParameter(ps, i + 1, value, jdbcType); } catch (TypeException | SQLException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } } } } }
PreparedStatementHandler.query @Override public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; //PreparedStatementLogger ps.execute(); //获取结果集DefaultResultSetHandler 处理结果集存储到List<T>里面 //DefaultResultSetHandler.handleResultSets return resultSetHandler.handleResultSets(ps); } ps.execute();? resultSetHandler.handleResultSets(ps); DefaultResultSetHandler.handleResultSets(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) { DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory); //storeObject handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null); multipleResults.add(defaultResultHandler.getResultList()); } else { handleRowValues(rsw, resultMap, resultHandler, rowBounds, null); } } } finally { // issue #228 (close resultsets) closeResultSet(rsw.getResultSet()); } } handleRowValues:handleRowValuesForNestedResultMap||handleRowValuesForSimpleResultMap(storeObject) 重要的方法 private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException { if (parentMapping != null) { // extend 类型的 linkToParents(rs, parentMapping, rowValue); } else { //DefaultResultHandler .handleResult结果添加到list 里面 callResultHandler(resultHandler, resultContext, rowValue); } } DefaultResultHandler.handleResult @Override public void handleResult(ResultContext<?> context) { //将结果添加到list 里面 list.add(context.getResultObject()); }
2.相关面试题:
1.Mapper类都是接口?那么具体的方法在哪里实现的?
MapperProxyFactory代理类实现的
3.常用类
org.apache.ibatis.builder:
annotation:
- MapperAnnotationBuilder解析@Mapper注解
- MethodResolver 创建MapperStatement对象
- ProviderSqlSource
xml:
- XMLConfigBuilder 解析configuration.xml配置文生成Configuration对象
- XMLMapperBuilder 解析Mapper.xml配置文件将接口类和Mapper.xml中namespace对应起来,解析xml中的Result 和Parameter
- XMLStatementBuilder 解析select\update\delete 标签 生成MapperStatement(包含SqlSource)