Mybatis-plus 源码执行全流程解析

上次更新时间2025-07-30 17:27:02阅读 0

Mybatis-plus 源码执行全流程解析

废话 少数流程开始:

1、业务入口:userMapper.insertBatch(entityList);

执行到代理类: $Proxy222 (com.sun.proxy) 开始走代理流程,然后到了代理类:

idea 执行流程取出栈信息:

 invoke:89, MybatisMapperProxy (com.baomidou.mybatisplus.core.override)

提前生成sqlSession ,地方如下:

2、代理类:public class MybatisMapperProxy implements InvocationHandler, Serializable

text
复制代码
// 当前代理类、方法名、保存的参数对象,可能多个 @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 {//核心接口进入,带着生成的sqlSession return cachedInvoker(method).invoke(proxy, method, args, sqlSession); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } }

来到:

text
复制代码
// private final Map<Method, MapperMethodInvoker> methodCache; 类似缓存操作 private MapperMethodInvoker cachedInvoker(Method method) throws Throwable { try {// 集合的操作方法,通过接口回调返回数据 return CollectionUtils.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 { return new PlainMethodInvoker(new MybatisMapperMethod(mapperInterface, method, sqlSession.getConfiguration())); } }); } catch (RuntimeException re) { Throwable cause = re.getCause(); throw cause == null ? re : cause; } }

 进入新的invoke 方法:

text
复制代码
@Override public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable { //private final MybatisMapperMethod mapperMethod 方法名对象 return mapperMethod.execute(sqlSession, args);//核心操作 }

3、来到 public class MybatisMapperMethod 类:

text
复制代码
// private final MapperMethod.MethodSignature method ;方法的类名 public Object execute(SqlSession sqlSession, Object[] args) { Object result; switch (command.getType()) {//MapperMethod.SqlCommand command; 对象 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); // TODO 这里下面改了 if (IPage.class.isAssignableFrom(method.getReturnType())) { result = executeForIPage(sqlSession, args); // TODO 这里上面改了 } else { 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、来到 public class MapperMethod 的内部类MethodSignature

text
复制代码
//private final ParamNameResolver paramNameResolver; 参数分解器 public Object convertArgsToSqlCommandParam(Object[] args) { return paramNameResolver.getNamedParams(args);//进入 }

5、来到:public class ParamNameResolver 

text
复制代码
public Object getNamedParams(Object[] args) { final int paramCount = names.size(); if (args == null || paramCount == 0) { return null; } else if (!hasParamAnnotation && paramCount == 1) { Object value = args[names.firstKey()]; return wrapToMapIfCollection(value, useActualParamName ? names.get(0) : null); } else { 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 + (i + 1); // ensure not to overwrite parameter named with @Param if (!names.containsValue(genericParamName)) { param.put(genericParamName, args[entry.getKey()]); } i++; } return param; } }

最后返回:

 下面重点分析:

text
复制代码
result = rowCountResult(sqlSession.insert(command.getName(), param));

点击 sqlSession.insert(command.getName(), param) 进入:三个实现类的其中一个

根据上游入口判断进入spring的类:

text
复制代码
public class SqlSessionTemplate implements SqlSession, DisposableBean

6、来到 SqlSessionTemplate

text
复制代码
//private final SqlSession sqlSessionProxy;方法的全路径、执行参数 @Override public int insert(String statement, Object parameter) { return this.sqlSessionProxy.insert(statement, parameter);//进入 }

三个实现类:

 来到子类 public class DefaultSqlSession implements SqlSession

7、DefaultSqlSession

text
复制代码
@Override public int insert(String statement, Object parameter) { return update(statement, parameter);//进入执行 }

来到:

text
复制代码
//private final Executor executor;执行器接口 //private final Configuration configuration; 配置类 @Override public int update(String statement, Object parameter) { try { dirty = true; MappedStatement ms = configuration.getMappedStatement(statement);//创建声明,进入 return executor.update(ms, wrapCollection(parameter));//正式执行 } catch (Exception e) { throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e); } finally { ErrorContext.instance().reset();//实例资源清除 } }

 点击configuration.getMappedStatement(statement) 进入

来到 public class MybatisConfiguration extends Configuration 此类为mybatisplus的类,继承的mybatis的配置类Configuration 。

8、MybatisConfiguration 类

text
复制代码
//此id就是mapper的全路径,在此服务中应该也是唯一的值 @Override public MappedStatement getMappedStatement(String id) { return this.getMappedStatement(id, true);//正式获取声明 }

来到:

text
复制代码
//protected final Map<String, MappedStatement> mappedStatements @Override public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) { if (validateIncompleteStatements) { buildAllStatements();//上游传的true,进入 } return mappedStatements.get(id);//在此处返回 }

点击: buildAllStatements() 进入父类Configuration,组装的细节后面我们会详细分享

text
复制代码
protected void buildAllStatements() { parsePendingResultMaps(); if (!incompleteCacheRefs.isEmpty()) { synchronized (incompleteCacheRefs) { incompleteCacheRefs.removeIf(x -> x.resolveCacheRef() != null); } } if (!incompleteStatements.isEmpty()) { synchronized (incompleteStatements) { incompleteStatements.removeIf(x -> { x.parseStatementNode(); return true; }); } } if (!incompleteMethods.isEmpty()) { synchronized (incompleteMethods) { incompleteMethods.removeIf(x -> { x.resolve(); return true; }); } } }

返回后进入 executor.update(ms, wrapCollection(parameter));进入切面类

text
复制代码
public class Plugin implements InvocationHandler
text
复制代码
//切面方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { Set<Method> methods = signatureMap.get(method.getDeclaringClass()); if (methods != null && methods.contains(method)) { //private final Interceptor interceptor;拦截器接口 return interceptor.intercept(new Invocation(target, method, args));//进入拦截器 } return method.invoke(target, args);//进行执行业务 } catch (Exception e) { throw ExceptionUtil.unwrapThrowable(e); } }

点击: 

来到:public class OptimisticLockerInterceptor implements Interceptor mybatis 中的类

text
复制代码
@Override @SuppressWarnings({"unchecked", "rawtypes"}) public Object intercept(Invocation invocation) throws Throwable { Object[] args = invocation.getArgs(); MappedStatement ms = (MappedStatement) args[0]; if (SqlCommandType.UPDATE != ms.getSqlCommandType()) { return invocation.proceed(); } Object param = args[1]; if (param instanceof Map) { Map map = (Map) param; //updateById(et), update(et, wrapper); Object et = map.getOrDefault(Constants.ENTITY, null); if (et != null) { // entity String methodId = ms.getId(); String methodName = methodId.substring(methodId.lastIndexOf(StringPool.DOT) + 1); TableInfo tableInfo = TableInfoHelper.getTableInfo(et.getClass()); if (tableInfo == null || !tableInfo.isWithVersion()) { return invocation.proceed(); } TableFieldInfo fieldInfo = tableInfo.getVersionFieldInfo(); Field versionField = fieldInfo.getField(); // 旧的 version 值 Object originalVersionVal = versionField.get(et); if (originalVersionVal == null) { return invocation.proceed(); } String versionColumn = fieldInfo.getColumn(); // 新的 version 值 Object updatedVersionVal = this.getUpdatedVersionVal(fieldInfo.getPropertyType(), originalVersionVal); if (PARAM_UPDATE_METHOD_NAME.equals(methodName)) { AbstractWrapper<?, ?, ?> aw = (AbstractWrapper<?, ?, ?>) map.getOrDefault(Constants.WRAPPER, null); if (aw == null) { UpdateWrapper<?> uw = new UpdateWrapper<>(); uw.eq(versionColumn, originalVersionVal); map.put(Constants.WRAPPER, uw); } else { aw.apply(versionColumn + " = {0}", originalVersionVal); } } else { map.put(Constants.MP_OPTLOCK_VERSION_ORIGINAL, originalVersionVal); } versionField.set(et, updatedVersionVal); return invocation.proceed(); } } return invocation.proceed();//点击进入 }

 来到:public class Invocation 

text
复制代码
public Object proceed() throws InvocationTargetException, IllegalAccessException { return method.invoke(target, args);//进入 }

到了:public final class Method extends Executable

text
复制代码
@CallerSensitive @ForceInline // to ensure Reflection.getCallerClass optimization @HotSpotIntrinsicCandidate public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (!override) { Class<?> caller = Reflection.getCallerClass(); checkAccess(caller, clazz, Modifier.isStatic(modifiers) ? null : obj.getClass(), modifiers); } MethodAccessor ma = methodAccessor; // read volatile if (ma == null) { ma = acquireMethodAccessor(); } return ma.invoke(obj, args);//进入 }

 进入:

三个实现类

9、来到 public class MybatisCachingExecutor implements Executor 实现类 mybatisplus包中

text
复制代码
@Override public int update(MappedStatement ms, Object parameterObject) throws SQLException { flushCacheIfRequired(ms);//刷新清除缓存,下次查询此表,会到数据库查,点击 // private final Executor delegate;执行器执行 return delegate.update(ms, parameterObject);//核心执行,点击 }

 来到:

text
复制代码
private void flushCacheIfRequired(MappedStatement ms) { Cache cache = ms.getCache(); if (cache != null && ms.isFlushCacheRequired()) { tcm.clear(cache);//清除缓存 } }

点击 delegate.update(ms, parameterObject);

10、到了 public abstract class BaseExecutor implements Executor

text
复制代码
@Override public int update(MappedStatement ms, Object parameter) throws SQLException { ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId()); if (closed) { throw new ExecutorException("Executor was closed."); } clearLocalCache();//清除缓存 return doUpdate(ms, parameter);//正式执行 }

点击:

text
复制代码
protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException;

抽象方法的重写:有mybatis和plus的两组实现

10、 到:public class MybatisSimpleExecutor extends AbstractBaseExecutor

text
复制代码
@Override public int doUpdate(MappedStatement ms, Object parameter) throws SQLException { Statement stmt = null; try { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);//生成执行的声明,里面很复杂,后期我们很专题讲解 stmt = prepareStatement(handler, ms.getStatementLog(), false);//拿数据源重点,进入 return stmt == null ? 0 : handler.update(stmt);//正式执行,点击 } finally { closeStatement(stmt);//关闭声明 } }

点击 prepareStatement(handler, ms.getStatementLog(), false);

text
复制代码
private Statement prepareStatement(StatementHandler handler, Log statementLog, boolean isCursor) throws SQLException { Statement stmt; Connection connection = getConnection(statementLog);//取数据源,进入 stmt = handler.prepare(connection, transaction.getTimeout());封装数据源到声明里 //游标不支持返回null. if (stmt == null && !isCursor) { return null; } else { handler.parameterize(stmt); return stmt; } }

11、到了父类  public abstract class BaseExecutor implements Executor

text
复制代码
protected Connection getConnection(Log statementLog) throws SQLException { // protected Transaction transaction; Connection connection = transaction.getConnection();//获取数据源,进入 if (statementLog.isDebugEnabled()) { return ConnectionLogger.newInstance(connection, statementLog, queryStack); } else { return connection; } }

 点击发现常用的三种实现:

显然 进入 mybatis-spring 包里的SpringManagedTransaction

12、来到 public class SpringManagedTransaction implements Transaction 类

text
复制代码
@Override public Connection getConnection() throws SQLException { if (this.connection == null) { openConnection();//获取连接,进入 } return this.connection; }

点击 openConnection()

text
复制代码
private void openConnection() throws SQLException { //通过spring的工具类DataSourceUtils 获取 数据库连接connection(JDK包里的),进入 this.connection = DataSourceUtils.getConnection(this.dataSource); this.autoCommit = this.connection.getAutoCommit();//自动提交的获取 //是否连接、事务的判断 this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource); LOGGER.debug(() -> "JDBC Connection [" + this.connection + "] will" + (this.isConnectionTransactional ? " " : " not ") + "be managed by Spring"); }

来到:

text
复制代码
public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException { try { return doGetConnection(dataSource);//点击 } catch (SQLException ex) { throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection", ex); } catch (IllegalStateException ex) { throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection: " + ex.getMessage()); } }

 点击:

text
复制代码
public static Connection doGetConnection(DataSource dataSource) throws SQLException { Assert.notNull(dataSource, "No DataSource specified"); ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource); if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) { conHolder.requested(); if (!conHolder.hasConnection()) { logger.debug("Fetching resumed JDBC Connection from DataSource"); conHolder.setConnection(fetchConnection(dataSource)); } return conHolder.getConnection(); } // Else we either got no holder or an empty thread-bound holder here. logger.debug("Fetching JDBC Connection from DataSource"); Connection con = fetchConnection(dataSource);//重点进入 if (TransactionSynchronizationManager.isSynchronizationActive()) { try { // Use same Connection for further JDBC actions within the transaction. // Thread-bound object will get removed by synchronization at transaction completion. ConnectionHolder holderToUse = conHolder; if (holderToUse == null) { holderToUse = new ConnectionHolder(con); } else { holderToUse.setConnection(con); } holderToUse.requested(); TransactionSynchronizationManager.registerSynchronization( new ConnectionSynchronization(holderToUse, dataSource)); holderToUse.setSynchronizedWithTransaction(true); if (holderToUse != conHolder) { TransactionSynchronizationManager.bindResource(dataSource, holderToUse); } } catch (RuntimeException ex) { // Unexpected exception from external delegation call -> close Connection and rethrow. releaseConnection(con, dataSource); throw ex; } } return con; }

来到:

text
复制代码
private static Connection fetchConnection(DataSource dataSource) throws SQLException { Connection con = dataSource.getConnection();//点击进入,dataSource 的实现类 if (con == null) { throw new IllegalStateException("DataSource returned null from getConnection(): " + dataSource); } return con; }

 点击:dataSource.getConnection()发现好的实现类,应该进入哪一个啊?? 

根据业务判断:进入NandaoDataSource        

text
复制代码
public class NandaoDataSource  extends AbstractTenantDataSource implements DataSource, NandaoDataSourceMXBean, MBeanRegistration, AutoCloseable{
text
复制代码
@Override public Connection getConnection() throws SQLException { if (provider == null) { throw new Exception("provider is null"); } return getConnection(provider.getUserId());//业务封装回去自定义数据源 }

进入

text
复制代码
public Connection getConnection(String userId) throws SQLException { for (int retry = 1; retry <= retryTimes; retry++) { UserDbInfo dbInfo = userDbInfoInfoService.getDatabaseInfo(userId); return getDataSource(dbInfo).getConnection(); } }

这是获取数据源的流程,分析到此,下篇我们分析真正执行数据库的流程 handler.update(stmt);,敬请期待!