mybatis

2018-10-09  本文已影响0人  来搞事情

参考:
https://blog.csdn.net/liming363873117/article/details/60467107
https://blog.csdn.net/u014297148/article/details/78696096

采用先代码块再解释的书写方式,比较混乱,暂时记一下,以后再整理。

Mybatis有以下几种组件
SqlSessionFactory
SqlSessionFactoryBuilder
Configuration
SqlSession

https://img-blog.csdn.net/20171202215246419?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDI5NzE0OA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast
  public SqlSessionFactory build(InputStream inputStream) {
    return build(inputStream, null, null);
  }

  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }
    
  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

Mybatis通过SqlSessionFactoryBuilder来构建SQLSessionFactory,在builder方法中传入配置文件的inputstream,然后会调用XMLConfigBuilder解析这个inputstream,封装都一个configuration对象里面,之后调用重载的参数是configuration的build方法new一个DefaultSqlSessionFactory对象,Configuration对象是对mybatis-config.xml配置文件的封装。也就是通过配置文件来构造一个SQLSessionFactory。

[图片上传失败...(image-94bfca-1539015708192)]

  @Override
  public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }

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

然后通过这个SQLSessionFactory的opensession来打开一个sqlsession,这个SQLSession就相当于jdbc编程的时候的那个connection对象,指一次数据库的会话。返回的是DefaultSession,此时这个SQLSession里面包含一个Configuration和一个Executor对象。

[图片上传失败...(image-a4b3cc-1539015708192)]

DefaultSqlSession.java

  @Override
  public <T> T getMapper(Class<T> type) {
    return configuration.<T>getMapper(type, this);
  }

Configuration.java

  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }

MapperRegistry.java

  @SuppressWarnings("unchecked")
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

之后通过java的动态代理,生成Mapper的代理类MapperProxy。需要传入 getMapper(Class<T> type),也就是接口名称。会在启动的时候生成所有的代理类。

下面进入SQL的执行阶段。

在这一块有四大对象
1、 Executor 执行器
2、 StatementHandler 数据库会话处理器,核心,起承上启下的作用
3、 ParameterHandler 参数处理器
4、 ResultSetHandler 结果处理器

有三种Executor,SimpleExecutor(默认),ReuseExecutor,BatchExecutor。Executor会调度StatementHandler、ParameterHandler、ResultHandler等来执行对应的SQL。

 @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    //判断是否有一级缓存
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }
  public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      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);
          result = sqlSession.selectOne(command.getName(), param);
        }
        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;
  }

调用方法的时候实际上是在执行MapperProxy的invoke方法,就是在调用对象代理类的invoke方法,在这个invoke方法里面,先判断一下method是不是Object的toString()等方法
if (Object.class.equals(method.getDeclaringClass()))),
如果不是则调用mapperMethod.execute(sqlSession, args);方法。在这个方法里面有一个switch判断是那种类型的SQL,select,update,delete等,然后调用sqlsession中对应的方法执行。

  @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      //从configuration中拿出SQL语句
      MappedStatement ms = configuration.getMappedStatement(statement);
      return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }
微信截图_20181009000029.png
  @Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }
  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    Connection connection = getConnection(statementLog);
    stmt = handler.prepare(connection, transaction.getTimeout());
    handler.parameterize(stmt);
    return stmt;
  }
  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    /此处调用原生sql的处理器
    PreparedStatement ps = (PreparedStatement) statement;
    //发出原生sql命令
    ps.execute();
    //采用ResultHandler结果处理器对结果集封装
    return resultSetHandler.<E> handleResultSets(ps);
  }

在这一步会从configuration中根据调用的方法名定位对应的SQL,MappedStatement对象。然后调用Executor对应的方法。之后会在Executor中通过configuration拿到一个StatementHandler,在prepareSatement方法中代用prepare方法提取出SQL语句,然后调用parameterize方法,通过ParameterHandler把参数设置进去。之后调用JDBC原生的SQL处理器处理SQL语句,然后对结果使用ResultHandler进行封装。

上一篇 下一篇

猜你喜欢

热点阅读