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.dry(反义词)__________________  2.writ...
复活节英文怎么说 复活节英文怎么说?复活节的英语翻译是什么?复活节:Easter;"Easter,anniversar...
2008年北京奥运会主题曲 2008年北京奥运会(第29届夏季奥林匹克运动会),2008年8月8日到2008年8月24日在中华人...
英语道歉信 英语道歉信15篇  在日常生活中,道歉信的使用频率越来越高,通过道歉信,我们可以更好地解释事情发生的...
六年级英语专题训练(连词成句... 六年级英语专题训练(连词成句30题)  1. have,playhouse,many,I,toy,i...
上班迟到情况说明英语   每个人都或多或少的迟到过那么几次,因为各种原因,可能生病,可能因为交通堵车,可能是因为天气冷,有...
小学英语教学论文 小学英语教学论文范文  引导语:英语教育一直都是每个家长所器重的,那么有关小学英语教学论文要怎么写呢...
英语口语学习必看的方法技巧 英语口语学习必看的方法技巧如何才能说流利的英语? 说外语时,我们主要应做到四件事:理解、回答、提问、...
四级英语作文选:Birth ... 四级英语作文范文选:Birth controlSince the Chinese Governmen...
金融专业英语面试自我介绍 金融专业英语面试自我介绍3篇  金融专业的学生面试时,面试官要求用英语做自我介绍该怎么说。下面是小编...
我的李老师走了四年级英语日记... 我的李老师走了四年级英语日记带翻译  我上了五个学期的小学却换了六任老师,李老师是带我们班最长的语文...
小学三年级英语日记带翻译捡玉... 小学三年级英语日记带翻译捡玉米  今天,我和妈妈去外婆家,外婆家有刚剥的`玉米棒上带有玉米籽,好大的...
七年级英语优秀教学设计 七年级英语优秀教学设计  作为一位兢兢业业的人民教师,常常要写一份优秀的教学设计,教学设计是把教学原...
我的英语老师作文 我的英语老师作文(通用21篇)  在日常生活或是工作学习中,大家都有写作文的经历,对作文很是熟悉吧,...
英语老师教学经验总结 英语老师教学经验总结(通用19篇)  总结是指社会团体、企业单位和个人对某一阶段的学习、工作或其完成...
初一英语暑假作业答案 初一英语暑假作业答案  英语练习一(基础训练)第一题1.D2.H3.E4.F5.I6.A7.J8.C...
大学生的英语演讲稿 大学生的英语演讲稿范文(精选10篇)  使用正确的写作思路书写演讲稿会更加事半功倍。在现实社会中,越...
VOA美国之音英语学习网址 VOA美国之音英语学习推荐网址 美国之音网站已经成为语言学习最重要的资源站点,在互联网上还有若干网站...
商务英语期末试卷 Part I Term Translation (20%)Section A: Translate ...