Mybatis工作流程

Mybatis初始化流程

1.获取配置文件(即获取一个InputStream)

2.创建SqlSessionFactoryBuilder对象

3.创建SqlSessionFactory对象(细分为3步)

 

3.创建SqlSessionFactory对象的过程

3.1构造XMLConfigBuilder对象(用于解析配置文件)

3.2解析配置文件(细分为多步)

3.3实例化SqlSessionFactory对象

 

3.2解析配置文件

简单叙述一下,即把xml里面的配置信息进行解析,并存储到Configuration的容器中。

 

 

总结

1.SqlSessionFactory是Mybatis的核心类,可以提供SqlSession,以SqlSession的形式执行SQL。

2.Configuration用于存储xml的配置信息如SQL等。

 

什么是SqlSession?

其实SqlSession只是一个门面,实际是由Executor来执行SQL的

 

SqlSessionMapper接口的关系是什么?(两种SQL执行的门面,现在多用Mapper)

SqlSession提供了一个getMapper方法,可以获取Mapper接口,看源码可知Mapper的Bean最终由动态代理实现。https://www.cnblogs.com/dongying/p/4142476.html

而Mapper的执行其实是通过Executor、StatementHandler、ParameterHandler和ResultHandler来完成数据操作和结果的返回。

 

Spring里面,每次都拿同一个Mapper Bean,如何在不同的connection下执行呢?

MapperProxy的代理如下:

  @Override

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    if (Object.class.equals(method.getDeclaringClass())) {

      try {

        return method.invoke(this, args);

      } catch (Throwable t) {

        throw ExceptionUtil.unwrapThrowable(t);

      }

    }

    final MapperMethod mapperMethod = cachedMapperMethod(method);

    return mapperMethod.execute(sqlSession, args);

  }

这里的sqlSession其实是一个SqlSessionTemple对象,在execute方法里面会调用SqlSessionTemple的方法(因为此时的SqlSession就是SqlSessionTemple),以update为例

  public Object execute(SqlSession sqlSession, Object[] args) {

    Object result;

    if (SqlCommandType.INSERT == command.getType()) {

      Object param = method.convertArgsToSqlCommandParam(args);

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

    } else if (SqlCommandType.UPDATE == command.getType()) {

      Object param = method.convertArgsToSqlCommandParam(args);

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

    } else if (SqlCommandType.DELETE == command.getType()) {

      Object param = method.convertArgsToSqlCommandParam(args);

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

    } else if (SqlCommandType.SELECT == command.getType()) {

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

        result = sqlSession.selectOne(command.getName(), param);

      }

    } else if (SqlCommandType.FLUSH == command.getType()) {

        result = sqlSession.flushStatements();

    } else {

      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;

  }

而进入SqlSessionTemple的方法其实都是走SqlSessionInterceptor代理

private class SqlSessionInterceptor implements InvocationHandler {

    @Override

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

      SqlSession sqlSession = getSqlSession(

          SqlSessionTemplate.this.sqlSessionFactory,

          SqlSessionTemplate.this.executorType,

          SqlSessionTemplate.this.exceptionTranslator);

      try {

        Object result = method.invoke(sqlSession, args);

        if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {

          // force commit even on non-dirty sessions because some databases require

          // a commit/rollback before calling close()

          sqlSession.commit(true);

        }

        return result;

      } catch (Throwable t) {

        Throwable unwrapped = unwrapThrowable(t);

        if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {

          // release the connection to avoid a deadlock if the translator is no loaded. See issue #22

          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);

          sqlSession = null;

          Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);

          if (translated != null) {

            unwrapped = translated;

          }

        }

        throw unwrapped;

      } finally {

        if (sqlSession != null) {

          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);

        }

      }

    }

  }

SqlSessionInterceptor代理中利用DefaultSqlSessionFactory重新创建了新的SqlSession(对应创建新的Executor,以替换SqlSessionTemple执行,以下是DefaultSqlSessionFactory创建SqlSession的方法

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {

    Transaction tx = null;

    try {

      final Environment environment = configuration.getEnvironment();

      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);

      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);

      final Executor executor = configuration.newExecutor(tx, execType);

      return new DefaultSqlSession(configuration, executor, autoCommit);

    } catch (Exception e) {

      closeTransaction(tx); // may have fetched a connection so lets call close()

      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);

    } finally {

      ErrorContext.instance().reset();

    }

  }

参考博客

https://blog.csdn.net/u010289197/article/details/55061222

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值