# mybatis3.5.6 **Repository Path**: wuyanzua/mybatis3.5.6 ## Basic Information - **Project Name**: mybatis3.5.6 - **Description**: mybatis源码解析 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-10-31 - **Last Updated**: 2022-11-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## Mybati一条sql的执行流程 总体来说,mybatis的查询流程分为以下几个部分: ```java class AutoConstructorTest { private static SqlSessionFactory sqlSessionFactory; @BeforeAll static void setUp() throws Exception { // create a SqlSessionFactory try (Reader reader = Resources.getResourceAsReader("org/apache/ibatis/autoconstructor/mybatis-config.xml")) { // 创建 SqlSessionFactory对象,参数为mybatis的总配置文件地址,选择的环境 sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader,"development"); } } @Test void fullyPopulatedSubject() { // 打开session try (SqlSession sqlSession = sqlSessionFactory.openSession()) { // 获取该mapper的代理对象 final AutoConstructorMapper mapper = sqlSession.getMapper(AutoConstructorMapper.class); // 通过代理对象调用该方法 final Object subject = mapper.getSubject(1); assertNotNull(subject); } } } ``` 步骤解析 一:构建SqlSessionFactory对象 1. 加载mybatis-config.xml文件 ```java Reader reader = Resources.getResourceAsReader("org/apache/ibatis/autoconstructor/mybatis-config.xml") ``` 2. 通过SqlSessionFactory中的重载方法build创建SqlSessionFactory对象,参数为mybatis的总配置文件地址 ```java // SqlSessionFactory类 public SqlSessionFactory build(Reader reader, String environment, Properties properties) { try { // 创建XMLConfigBuilder 对象 XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties); // 解析总配置文件,返回一个DefaultSqlSessionFactory对象 // 解析XML parser.parse() return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { reader.close(); } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } } ``` 3. build方法中创建解析xml的XMLConfigBuilder对象,同时创建整体的配置对象Configuration ```java // XMLConfigBuilder类 public XMLConfigBuilder(Reader reader, String environment, Properties props) { // 创建XML解析器 this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props); } private XMLConfigBuilder(XPathParser parser, String environment, Properties props) { super(new Configuration()); ErrorContext.instance().resource("SQL Mapper Configuration"); this.configuration.setVariables(props); this.parsed = false; this.environment = environment; this.parser = parser; } ``` 4. 调用XMLConfigBuilder中的parse()方法开始解析mybatis-config.xml文件 5. 调用parseConfiguration方法解析配置文件中的/configuration节点中的内容 ```java // XMLConfigBuilder类 public Configuration parse() { if (parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); } parsed = true; // 解析总配置文件 parseConfiguration(parser.evalNode("/configuration")); return configuration; } ``` 6. 开始解析各种字节点,比如typeAliases,plugins,environments,mappers等,其核心就是往Configuration对象中设置对应属性 ```java // XMLConfigBuilder类 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")); // plugins,设置拦截器链 pluginElement(root.evalNode("plugins")); objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); reflectorFactoryElement(root.evalNode("reflectorFactory")); settingsElement(settings); // environments,设置数据源,tx相关信息 environmentsElement(root.evalNode("environments")); databaseIdProviderElement(root.evalNode("databaseIdProvider")); // 解析typeHandlers,类型处理类 typeHandlerElement(root.evalNode("typeHandlers")); // 解析mapper,处理sql相关信息 mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } } ``` 7. 例如: ```java // XMLConfigBuilder类 // pluginElement(root.evalNode("plugins"));方法其实就是往Configuration对象中的interceptorChain熟悉中添加设置的plugin private void pluginElement(XNode parent) throws Exception { if (parent != null) { for (XNode child : parent.getChildren()) { String interceptor = child.getStringAttribute("interceptor"); Properties properties = child.getChildrenAsProperties(); Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).getDeclaredConstructor().newInstance(); interceptorInstance.setProperties(properties); configuration.addInterceptor(interceptorInstance); } } } ``` 8. 各种解析完成之后得到一个Configuration对象 9. 通过build重载方法构建一个DefaultSqlSessionFactory对象返回 ```java public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); } ``` 二:从sqlSessionFactory对象中获取SqlSession对象 1. 调用DefaultSqlSessionFactory中的openSession()方法,其内部调用的是openSessionFromDataSource()方法 ```java SqlSession sqlSession = sqlSessionFactory.openSession() // DefaultSqlSessionFactory类 @Override public SqlSession openSession() { return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); } ``` 2. 获取环境Environment拿到事务工厂TransactionFactory,通过事务工厂拿到事务处理器Transaction,默认是JdbcTransaction ```java private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { // 获取环境 final Environment environment = configuration.getEnvironment(); final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); // 拿到事务,默认是JDBC 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(); } } ``` 3. 创建执行器Executor,默认是CachingExecutor,遍历Configuration对象中的interceptorChain属性里的值,使用JDK的动态代理去不断代理CachingExecutor ```java // Configuration类 public Executor newExecutor(Transaction transaction, ExecutorType 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); } // cacheEnabled默认是true,所以还是会使用CachingExecutor,不知何意 if (cacheEnabled) { executor = new CachingExecutor(executor); } // 循环遍历所有拦截器进行代理 executor = (Executor) interceptorChain.pluginAll(executor); return executor; } // InterceptorChain类 /** * 例如现在有拦截器 interceptor1,interceptor2 * 遍历这两个,首先target = CachingExecutor * 第一次遍历 target = 经过interceptor1代理过后的CachingExecutor * 第二次 target = 经过interceptor2代理过后的(经过interceptor1代理过后的CachingExecutor) * 所以在后期调用也会遍历调用拦截器Plugin中的invoke方法 * @param target Executor * @return */ public Object pluginAll(Object target) { // 循环遍历所有拦截器,开启套娃的代理模式 for (Interceptor interceptor : interceptors) { // 给所有的拦截器创建代理对象 target = interceptor.plugin(target); } return target; } // Interceptor接口 default Object plugin(Object target) { return Plugin.wrap(target, this); } // Plugin类,实现了jdk的动态代理的接口 public class Plugin implements InvocationHandler public static Object wrap(Object target, Interceptor interceptor) { // 获取到拦截器类上的一些注解的信息 Map Map, Set> signatureMap = getSignatureMap(interceptor); Class type = target.getClass(); // 获取该 Executor 实现类上实现的所有接口 Class[] interfaces = getAllInterfaces(type, signatureMap); if (interfaces.length > 0) { // 创建代理对象 return Proxy.newProxyInstance( // 用哪个类加载器去加载代理对象 type.getClassLoader(), // 动态代理类需要实现的接口 interfaces, // 动态代理方法在执行时,会调用下方对象里面的invoke方法去执行 new Plugin(target, interceptor, signatureMap)); } return target; } ``` 4. 创建DefaultSqlSession对象并返回 ```java return new DefaultSqlSession(configuration, executor, autoCommit); ``` 三:获取指定mapper的代理对象 1. 调用DefaultSqlSession中的getMapper方法,实际是调用到了MapperRegistry中的getMapper方法 ```java // MapperRegistry类 /** * knownMappers的添加请看下方方法 * @see XMLMapperBuilder#parse(), XMLMapperBuilder#bindMapperForNamespace() * @return */ public T getMapper(Class type, SqlSession sqlSession) { final MapperProxyFactory mapperProxyFactory = (MapperProxyFactory) 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); } } ``` 2. 通过mapperProxyFactory和Jdk的动态代理构建出通过MapperProxy代理过的目标对象 ```java protected T newInstance(MapperProxy mapperProxy) { return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); } // public class MapperProxy implements InvocationHandler, Serializable { ... } public T newInstance(SqlSession sqlSession) { final MapperProxy mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); } ``` 四:通过代理对象调用目标方法 1. 调用MapperProxy中的invoke方法,调用cachedInvoker返回PlainMethodInvoker对象,并创建了MapperMethod对象 ```java // MapperProxy类 @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 { // cachedInvoker返回MapperMethodInvoker return cachedInvoker(method).invoke(proxy, method, args, sqlSession); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } } ``` 2. 调用PlainMethodInvoker中的invoke方法,调用MapperMethod对象中的execute方法 ```java @Override public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable { return mapperMethod.execute(sqlSession, args); } ``` 3. 判断sql的执行类型是crud的哪一种,此次调用到了DefaultSqlSession中的selectOne方法 ```java // MapperMethod类 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; } ``` 4. 重载调用到了DefaultSqlSession中的selectList方法,从而调用Executor对象中的query方法 ```java // DefaultSqlSession类 private List selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) { try { MappedStatement ms = configuration.getMappedStatement(statement); // executor = new Plugin() return executor.query(ms, wrapCollection(parameter), rowBounds, handler); } catch (Exception e) { throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } } ``` 5. 因为Executor(CachingExecutor)对象被Plugin对象代理过,所有先会调用Plugin中的invoke方法 ```java /** * @param proxy CachingExecutor的代理对象 * @param method Executor.query()方法 * @param args [String statement, Object parameter, RowBounds rowBounds, ResultHandler handle] * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { // 获取Executor中需要执行的方法,在上方wrap中进行赋值进去,也就是说在自定义的拦截器上类的注解里面的方法 Set methods = signatureMap.get(method.getDeclaringClass()); if (methods != null && methods.contains(method)) { // target = CachingExecutor的代理对象 注意:因为是套娃式的代理,所以此处会循环调用所有 return interceptor.intercept(new Invocation(target, method, args)); } return method.invoke(target, args); } catch (Exception e) { throw ExceptionUtil.unwrapThrowable(e); } } ``` 6. Plugin中的invoke检验此次查询的方法时候在拦截器的类的注解上面,如果在就调用自己写的拦截器的intercept方法 7. 执行完扩展逻辑后,正式调用query方法 8. 调用query方法生产二级缓存的key动态sqlBoundSql对象,调用重载方法 9. 如果开启了二级缓存就先查缓存,没有就直接进行查询 ```java // CachingExecutor类 @Override public List 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); } @Override public List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { // 如果mapper.xml文件中配置了二级缓存,解析mapper文件的时候会往这个里面塞 Cache cache = ms.getCache(); if (cache != null) { // 如果需要刷新缓存的话就刷新:flushCache="true" flushCacheIfRequired(ms); if (ms.isUseCache() && resultHandler == null) { ensureNoOutParams(ms, boundSql); // 查询二级缓存 @SuppressWarnings("unchecked") List list = (List) tcm.getObject(cache, key); if (list == null) { // 如果没有值,则执行查询,这个查询实际也是先走一级缓存查询,一级缓存也没有的话,则进行DB查询 list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); // 设置缓存 tcm.putObject(cache, key, list); // issue #578 and #116 } return list; } } /** * delegate = SimpleExecutor多层嵌套代理 * @see org.apache.ibatis.session.Configuration#newExecutor() * @see BaseExecutor#query() */ return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); } ``` 10. 调用BaseExecutor方法中的query方法,此方法先查一级缓存,没有就查数据库 ```java // BaseExecutor类 @Override public List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { BoundSql boundSql = ms.getBoundSql(parameter); // 一级缓存Key CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql); return query(ms, parameter, rowBounds, resultHandler, key, boundSql); } @SuppressWarnings("unchecked") @Override public List 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) { throw new ExecutorException("Executor was closed."); } if (queryStack == 0 && ms.isFlushCacheRequired()) { clearLocalCache(); } List list; try { queryStack++; // 查询一级缓存 list = resultHandler == null ? (List) 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) { // issue #482 clearLocalCache(); } } return list; } ``` 11. 调用SimpleExecutor中的doQuery方法,创建了基于RoutingStatementHandler代理后的对象,并且创建连接开始对数据库对象Statement进行预编译,设置参数 ```java // SimpleExecutor类 @Override public List 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); // 获取jdbc连接,预编译,设置参数 stmt = prepareStatement(handler, ms.getStatementLog()); return handler.query(stmt, resultHandler); } finally { closeStatement(stmt); } } private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; // 获取jdbc连接 Connection connection = getConnection(statementLog); // BaseStatementHandler中的prepare // handler = RoutingStatementHandler // 内部进行了sql语句预编译 stmt = handler.prepare(connection, transaction.getTimeout()); // 开始转换sql语句,设置参数 handler.parameterize(stmt); return stmt; } ``` 12. 调用PreparedStatementHandler中的query方法正式查询数据库 ```java @Override public List query(Statement statement, ResultHandler resultHandler) throws SQLException { String sql = boundSql.getSql(); statement.execute(sql); return resultSetHandler.handleResultSets(statement); } ``` 13. 通过ResultSetHandler对象处理返回结果,从此查询流程结束