Mybatis-plus 源码执行全流程解析
创始人
2024-03-29 19:46:29
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

    // 当前代理类、方法名、保存的参数对象,可能多个@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {if (Object.class.equals(method.getDeclaringClass())) {return method.invoke(this, args);} else {//核心接口进入,带着生成的sqlSessionreturn cachedInvoker(method).invoke(proxy, method, args, sqlSession);}} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}}

来到:

// private final Map 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 方法:

        @Overridepublic 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 类:

// 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

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

5、来到:public class ParamNameResolver 

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 param = new ParamMap<>();int i = 0;for (Map.Entry 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 @Paramif (!names.containsValue(genericParamName)) {param.put(genericParamName, args[entry.getKey()]);}i++;}return param;}}

最后返回:

 下面重点分析:

result = rowCountResult(sqlSession.insert(command.getName(), param));

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

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

public class SqlSessionTemplate implements SqlSession, DisposableBean

  6、来到 SqlSessionTemplate

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

三个实现类:

 来到子类 public class DefaultSqlSession implements SqlSession

 7、DefaultSqlSession

  @Overridepublic int insert(String statement, Object parameter) {return update(statement, parameter);//进入执行}

来到:

 //private final Executor executor;执行器接口//private final Configuration configuration; 配置类@Overridepublic 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 类

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

来到:

   //protected final Map mappedStatements @Overridepublic MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {if (validateIncompleteStatements) {buildAllStatements();//上游传的true,进入}return mappedStatements.get(id);//在此处返回}

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

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));进入切面类

public class Plugin implements InvocationHandler
  //切面方法@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {Set 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 中的类

@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) {// entityString 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 

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

到了:public final class Method extends Executable

    @CallerSensitive@ForceInline // to ensure Reflection.getCallerClass optimization@HotSpotIntrinsicCandidatepublic 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 volatileif (ma == null) {ma = acquireMethodAccessor();}return ma.invoke(obj, args);//进入}

 进入:

三个实现类

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

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

 来到:

 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

  @Overridepublic 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);//正式执行}

点击:

  protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException;

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

10、 到:public class MybatisSimpleExecutor extends AbstractBaseExecutor

    @Overridepublic 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);

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

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

10、来到 public class SpringManagedTransaction implements Transaction 类

 @Overridepublic Connection getConnection() throws SQLException {if (this.connection == null) {openConnection();//获取连接,进入}return this.connection;}

点击 openConnection()

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");}

来到:

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());}}

 点击:

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;}

来到:

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        

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

进入

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);,敬请期待!

 

相关内容

热门资讯

春节联欢晚会主持词开场白   翻开精美的日历,我细数着春节将要来临。那是我们中华民族的传统节日,更是我期盼的佳节,因为只有这几...
真爱至上中英文经典台词 真爱至上中英文经典台词  1、All I want for Christmas is you.  今...
欢聚一堂舞蹈主持词 欢聚一堂舞蹈主持词  串词是在晚会、联欢会等大型联欢活动中,主持人把前后节目,把整台节目恰到好处的联...
主持词结束语 主持词结束语(通用12篇)  利用在中国拥有几千年文化的诗词能够有效提高主持词的感染力。在人们越来越...
秋季小学开学典礼校长的致辞 秋季小学开学典礼校长的致辞(通用13篇)  在学习、工作、生活中,许多人都有过写致辞的经历,对致辞都...
五月的主持词开场白 五月的主持词开场白  主持人在台上表演的灵魂就表现在主持词中。在当下这个社会中,各种场合中活跃现场气...
重阳节优秀致辞 重阳节优秀致辞范文  无论是身处学校还是步入社会,大家都用到过致辞吧,在各种重大的庆典、外交、纪念活...
QQ群晚会开幕词 QQ群晚会开幕词  QQ群晚会开幕词    尊贵的各位嘉宾,群主,各位管理,群友们大家晚上好:   ...
主持谢幕词 主持谢幕词范本  篇一:主持谢幕词  愿一切荣耀、尊贵、颂赞都归给至高上帝!  都说“台上一分钟,台...
圣诞节联欢晚会主持词 圣诞节联欢晚会主持词  主持词的写作需要将主题贯穿于所有节目之中。在一步步向前发展的社会中,主持词与...
元宵节的主持词 元宵节的主持词  一般在节日的时候,都是会举行一些活动的,尤其是在元宵节这个大型的节日。下面是小编为...
初中生晨会主持词 初中生晨会主持词(通用5篇)  主持词要尽量增加文化内涵、寓教于乐,不断提高观众的文化知识和素养。现...
晨会主持词开场白   开晨会是公司职场管理的规章制度,那么公司晨会主持如何开场白好呢?以下是小编为大家搜集整理提供到的...
企业年会主持词 企业年会主持词  主持词是主持人在台上表演的灵魂之所在。在人们越来越多的参与各种活动的今天,主持词是...
企业晚会的主持词 企业晚会的主持词  借鉴诗词和散文诗是主持词的一种写作手法。在人们越来越多的参与各种活动的今天,主持...
年终总结会主持词 2021年终总结会主持词范文(精选13篇)  契合现场环境的主持词能给集会带来双倍的效果。现今社会在...
半台词爆笑 三句半台词大全爆笑  三句半是一种中国民间群众传统曲艺表演形式,下面是为带大家整理的爆笑的'三句半台...
三八妇女节活动主持词 三八妇女节活动主持词3篇  三月的春风拂过我们脚下的土地,三月的惊雷敲响了我们奋进的汽笛,三月我们迎...
文艺晚会主持人主持词 文艺晚会主持人主持词(精选10篇)  主持词是各种演出活动和集会中主持人串联节目的串联词。在当下这个...
校园文艺晚会结束语 下面文艺晚会结束语是小编为你们寻找的,希望你们会喜欢喔文艺晚会结束语一女1:最明快的,莫过于一年一度...