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

 

相关内容

热门资讯

二年级作文不少于200个字【... 二年级作文不少于600个字 篇一我的暑假生活暑假终于来了,我迫不及待地迎接了这个长假。在这个暑假里,...
二年级暑假趣事作文捉老鼠(推... 二年级暑假趣事作文捉老鼠 篇一暑假快到了,我和弟弟决定在家里玩捉老鼠的游戏。我们找来了一些小道具,准...
小学二年级避暑山庄旅游作文(... 小学二年级避暑山庄旅游作文 篇一我和家人去了一个非常有趣的地方——避暑山庄。这个地方真的很美,有很多...
二年级作文游庐山【精简6篇】 二年级作文游庐山 篇一我和爸爸妈妈一起去了庐山。庐山是中国著名的山岳风景区,被誉为“江南第一山”。我...
二年级下册看图写话春天来了作... 二年级下册看图写话春天来了作文 篇一春天来了春天来了,大地变得生机勃勃。图中的小朋友们正在户外玩耍,...
二年级打雪仗作文指导【通用6... 二年级打雪仗作文指导 篇一打雪仗是冬天最有趣的活动之一,对于二年级的小朋友来说,更是一种享受。下面是...
二年级美丽的早晨作文(实用6... 二年级美丽的早晨作文 篇一美丽的早晨早晨的阳光透过窗户洒进来,房间里弥漫着一股清新的味道。我慢慢睁开...
小学二年级海边旅游作文200... 小学二年级海边旅游作文200字作文 篇一我和家人去海边旅游了,真是一个美好的经历!早上,我们一大早就...
二年级【优秀6篇】 二年级 篇一:我的暑假生活暑假终于来了,我迫不及待地开始了我的暑假生活。在这个悠长的假期里,我过得非...
赏荷花二年级作文【通用6篇】 赏荷花二年级作文 篇一欣赏荷花的美丽今天,我和爸爸妈妈一起去公园赏荷花。公园里有一个大大的荷花池,里...
舞蹈汇演作文二年级【精彩6篇... 舞蹈汇演作文二年级 篇一舞蹈汇演是一场精彩绝伦的表演,让我感受到了舞蹈的魅力和美妙。我在二年级的时候...
二年级作文我家的厨师(优质6... 二年级作文我家的厨师 篇一我家的厨师是我妈妈。她是一个非常厉害的厨师,每天都能给我们做出美味可口的饭...
童年趣事作文:枕头大战【精选... 童年趣事作文:枕头大战 篇一小时候的我总是充满了无尽的精力和好奇心,每天都在探索世界的各个角落。而最...
家乡的菊花作文二年级(经典6... 家乡的菊花作文二年级 篇一家乡的菊花我家乡是一个美丽的小镇,四季如春,花草繁盛。其中,最引人注目的要...
二年级小作文28篇【精简3篇... 二年级小作文28篇 篇一我最喜欢的动物我最喜欢的动物是猫。猫咪有软软的毛,尤其是它们的小脸上,摸起来...
二年级写我的家乡【优选6篇】 二年级写我的家乡 篇一我的家乡是一个美丽的小城镇。它位于一个宽广的山谷之中,四周环绕着青翠欲滴的群山...
春雨小学二年级作文300字【... 春雨小学二年级作文300字 篇一:我的偶像我的偶像是我的爸爸。他是一个非常勤劳、聪明和有责任心的人。...
秋节作文【实用6篇】 秋节作文 篇一:传统与现代的秋节庆祝方式秋节是中国传统的重要节日之一,也是我最喜欢的节日之一。在这个...
鱼儿的作文二年级(优秀6篇) 鱼儿的作文二年级 篇一我喜欢鱼儿我是一条小小鱼儿,生活在清澈见底的小溪里。我有一个漂亮的鱼尾巴,闪闪...
二年级语文下册四字词语知识(... 二年级语文下册四字词语知识 篇一在二年级的语文下册中,学生将会接触到一些四字词语的知识。这些四字词语...