mybatis源码分析(二) 执行流程分析
mybatis源码分析(二) 执行流程分析
一丶环境准备
准备只使用mybatis的环境,去掉spring等框架,方便分析
二丶从SqlSession#openSession()开始分析
//org.apache.ibatis.session.defaults.DefaultSqlSessionFactory
public SqlSession openSession() { return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); // 默认是不自动提交 }
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { final Environment environment = configuration.getEnvironment(); // 获取配置的环境, 包括事务管理, 和jdbc数据源 final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); // 获取执行器,默认是SimpleExecutor final Executor executor = configuration.newExecutor(tx, execType); // 返回sqlSession (sqlSession是接口层, 封装了许多客户端常用的方法) 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(); } }
三丶获取mapper实体类
DefaultSqlSession
@Override public <T> T getMapper(Class<T> type) { return configuration.getMapper(type, this); }
Configuration
public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return mapperRegistry.getMapper(type, sqlSession); }
MapperRegistry
@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); //mapper代理工厂, 生成对应的代理对象 } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } }
四丶MapperProxyFactory动态代理生成对应的代理类
public T newInstance(SqlSession sqlSession) { //使用jdk动态代理, 需要实现jdk的接口, mapperProxy实现了对应的接口方法 final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); } protected T newInstance(MapperProxy<T> mapperProxy) { //使用jdk生成动态代理对象 return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); }
五丶调用Mapper方法, 实际调用MapperProxy代理方法
一个MapperProxy对应一个Mapper实体类, MapperProxy会缓存Mappper实体类的所有方法调用
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)) { //接口的default方法 return invokeDefaultMethod(proxy, method, args); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } // 最后使用mapperMethod调用执行对应的mapperedStatement, 可以说是真正执行sql语句的入口 // 这些动态代理, 只是为方便开发者使用对应方法, 而将执行语句与对应方法绑定而设计的 final MapperMethod mapperMethod = cachedMapperMethod(method); return mapperMethod.execute(sqlSession, args); } private MapperMethod cachedMapperMethod(Method method) { return methodCache.computeIfAbsent(method, k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration())); }
六丶MapperMethod分发调用sqlSession执行对应的方法
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; 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); // 解析对应的方法参数名 // 最后使用SqlSession执行对应的方法 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; } public Object convertArgsToSqlCommandParam(Object[] args) { return paramNameResolver.getNamedParams(args); }
ParamNameResolver 用于解析方法中的注解参数名
/** * <p> * A single non-special parameter is returned without a name. * Multiple parameters are named using the naming rule. * In addition to the default names, this method also adds the generic names (param1, param2, * ...). * </p> */ public Object getNamedParams(Object[] args) { final int paramCount = names.size(); if (args == null || paramCount == 0) { return null; } else if (!hasParamAnnotation && paramCount == 1) { return args[names.firstKey()]; } else { // 根据@Param中的值, 以及方法参数 , 设置成map final Map<String, Object> param = new ParamMap<>(); int i = 0; for (Map.Entry<Integer, String> entry : names.entrySet()) { param.put(entry.getValue(), args[entry.getKey()]); // add generic param names (param1, param2, ...) final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1); // ensure not to overwrite parameter named with @Param if (!names.containsValue(genericParamName)) { param.put(genericParamName, args[entry.getKey()]); } i++; } return param; } }
七丶DefaultSqlSession#selectOne()真正开始执行 (执行入口)
@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; } } @Override public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { try { // 根据方法名, 从配置中获取对应的以根据配置解析出来的sql执行封装信息 -- mappedStatement MappedStatement ms = configuration.getMappedStatement(statement); // 最后由执行器执行 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(); } }
八丶执行器执行
本次SqlSession默认使用SimpleExecutor, SqlSession先调用执行simpleExecutor父类BaseExecutor#query()方法
1) BaseExecutor
主要是做了本地缓存, 然后查询功能(doQuery)由子类实现
protected BaseExecutor(Configuration configuration, Transaction transaction) { this.transaction = transaction; this.deferredLoads = new ConcurrentLinkedQueue<>(); this.localCache = new PerpetualCache("LocalCache"); // 在执行器中, 使用Propertual做本地缓存, 它其实就是一个Map this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache"); this.closed = false; this.configuration = configuration; this.wrapper = this; } @SuppressWarnings("unchecked") @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) { throw new ExecutorException("Executor was closed."); } if (queryStack == 0 && ms.isFlushCacheRequired()) { 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) { // 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 { 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; } protected Connection getConnection(Log statementLog) throws SQLException { Connection connection = transaction.getConnection(); // 最后是由事务管理器获取对应的连接 if (statementLog.isDebugEnabled()) { return ConnectionLogger.newInstance(connection, statementLog, queryStack); } else { return connection; } }
2) SimpleExecutor#doQuery() ( 子类实现doQuery() )
主要分成两步, 1. StatementHandler处理并执行对应的statement方法, 2. ResultSetHandler处理包装转换结果
@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统一实例化封装对应的stamentHandler, 主要是用于插件链的包装 StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); // 预编译对应的statement , transaction获取连接, 然后由statementHanlder预编译对应statement // 以及转换参数类型并设置对应的参数给stmt stmt = prepareStatement(handler, ms.getStatementLog()); // 由handler执行查询 // resultHandler处理查询的结果 return handler.query(stmt, resultHandler); } finally { closeStatement(stmt); } } private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; Connection connection = getConnection(statementLog); //调用BaseExecutor中的getConnection方法, 最后委派给事务管理器获取对应的连接 stmt = handler.prepare(connection, transaction.getTimeout()); handler.parameterize(stmt); return stmt; }
configuration#newStatementHandler()
生成StatementHandler()的同时, 给它装配上插件
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { // routingStatementHandler的作用主要是根据mappedStatement的类型, 生成对应类型的StatementHandler StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); // 然后为该statementHandler添加拦截器 statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler); return statementHandler; }
PreparedStatementHandler#query() 真正执行Sql语句
@Override public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; ps.execute(); // 调用jdbc中的statment执行方法 // 然后由结果集处理器处理返回结果 return resultSetHandler.handleResultSets(ps); }
DefaultResultSetHandler#handleResultSets()处理转换返回结果
@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; ResultSetWrapper rsw = getFirstResultSet(stmt); List<ResultMap> resultMaps = mappedStatement.getResultMaps(); int resultMapCount = resultMaps.size(); validateResultMapsCount(rsw, resultMapCount); while (rsw != null && resultMapCount > resultSetCount) { ResultMap resultMap = resultMaps.get(resultSetCount); handleResultSet(rsw, resultMap, multipleResults, null); rsw = getNextResultSet(stmt); cleanUpAfterHandlingResultSet(); 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); }
九丶执行流程总结
人生没有彩排,每一天都是现场直播