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

 

相关内容

热门资讯

关于危急时刻的四年级作文50... 关于危急时刻的四年级作文500字 篇一危急时刻在我们的生活中,我们常常会遇到一些危急时刻,这些时刻需...
我最敬佩的一位名人四年级作文... 我最敬佩的一位名人四年级作文 篇一我最敬佩的一位名人是李彦宏。李彦宏是中国著名的企业家,同时也是百度...
感恩老师四年级作文600字【... 篇一:感恩老师的温暖我是一名四年级的学生,今天我要写一篇关于感恩老师的作文。老师是我们成长道路上最重...
做家务的作文400字四年级作... 做家务的作文400字四年级作文20篇篇一:我喜欢做家务我是一个四年级的小学生,我喜欢做家务。每天放学...
四年级写作文买菜400字(经... 四年级写作文买菜400字 篇一:去菜市场买菜四年级的我,有一次和妈妈一起去菜市场买菜,这是我第一次亲...
四年级下册数学暑假新时空答案... 四年级下册数学暑假新时空答案 篇一在四年级下册的数学学习中,我们将继续探索数学的奥秘和应用。而暑假正...
地雷花四年级作文【最新3篇】 地雷花四年级作文 篇一地雷花地雷花是一种奇特的植物,它的花朵看起来像一颗小小的地雷。我在学校的花坛里...
我和孙悟空的一天四年级上册作... 我和孙悟空的一天四年级上册作文 篇一今天是一个特殊的日子,我竟然和孙悟空一起度过了一天!早上,我醒来...
推荐一个好地方作文四年级45... 推荐一个好地方作文四年级450字 篇一我的家乡是一个非常美丽的地方,我推荐大家来参观一下。我家乡的风...
小学的小学四年级作文500字... 小学的小学四年级作文500字 篇一我喜欢的运动我是一个活泼好动的小女孩,喜欢参加各种运动。今天我就来...
今天我当家四年级作文(推荐6... 今天我当家四年级作文 篇一我当家的一天今天,我得到了一个特殊的任务,那就是要当家一天。这是我第一次担...
跳绳比赛四年级作文(通用6篇... 跳绳比赛四年级作文 篇一跳绳比赛的经历我是一名四年级的学生,最近我们学校举办了一场跳绳比赛。这是我第...
家乡变化作文400字四年级(... 家乡变化作文400字四年级 篇一家乡变化我爱我的家乡,那是一个美丽而又宁静的地方。然而,自从几年前,...
一件高兴的事250作文四年级... 篇一:一件高兴的事今天,我要给大家讲一个让我非常高兴的事情。那天,我和妈妈一起去超市买东西。在超市里...
四年级写大自然的景色作文30... 四年级写大自然的景色作文300字 篇一大自然的美景大自然是我们共同的母亲,给予我们无尽的美景和宝贵的...
小小动物园四年级作文【精简6... 小小动物园四年级作文 篇一我参观了一个小小的动物园,里面有许多有趣的动物。首先,我看到了一只可爱的小...
小小动物园四年级作文(精简6... 小小动物园四年级作文 篇一我参观了一个小小的动物园,这是我第一次看到这么多不同种类的动物。动物园里有...
悔恨400字作文【实用3篇】 悔恨400字作文 篇一悔恨是一种深深的内心痛苦,当我们回首往事,发现自己的错误和过失时,心中不禁涌起...
我的奇思妙想四年级作文350... 我的奇思妙想四年级作文350字 篇一我曾经有一个奇思妙想,那就是创造一个可以让人们实现任何愿望的神奇...
小树长高了四年级作文【精简3... 小树长高了四年级作文 篇一四年级的时候,我们班上有一棵小树。那时候,它只有一米多高,细细的树干上长满...