MyBatis的Sql执行过程源码解读

1.先获得SqlSessionFactory

         通过SqlSessionFactoryBuilder去读取mybatis的配置文件,然后build一个DefaultSqlSessionFactory。

/**
   * 一系列的构造方法最终都会调用本方法(配置文件为Reader时会调用本方法,还有一个InputStream方法与此对应)
   * @param reader
   * @param environment
   * @param properties
   * @return
   */
  public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
      //通过XMLConfigBuilder解析配置文件,解析的配置相关信息都会封装为一个Configuration对象
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
      //这儿创建DefaultSessionFactory对象
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        reader.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }


2.通过SqlSessionFactory去获取SqlSession对象

  public SqlSession openSession() 
  {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }
	  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) 
	  {
		    Transaction tx = null;
		    try 
		    {
		      //通过Configuration对象去获取相关的配置信息,Environment对象包含了数据源和事务的配置
		      final Environment environment = configuration.getEnvironment();
		      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
		      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
		      //实际上就是Executor来执行sql语句,executor是对于Statement的封装
		      final Executor executor = configuration.newExecutor(tx, execType, autoCommit);
		      //创建DefaultSqlSession对象
		      return new DefaultSqlSession(configuration, executor);
		    }
		    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();
		    }
		  }
                      这样就获得了SqlSession对象


3.通过SqlSession获得Mapper

  public <T> T getMapper(Class<T> type) 
  {
    return configuration.<T>getMapper(type, this);
  }
            这里通过Configuration的getMapper方法来获得

  public <T> T getMapper(Class<T> type, SqlSession sqlSession) 
  {
    return mapperRegistry.getMapper(type, sqlSession);
  }
  protected MapperRegistry mapperRegistry = new MapperRegistry(this);

     继续看MapperRegistry的getMapper方法

	  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);   //此处使用反射,生成一个MapperProxyFactory对象
		    }
		    catch (Exception e) 
		    {
		      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
		    }
	  }
  private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: rgb(255, 255, 255);">            </span>

         knownMappers在读取配置文件的时候,已经将mapper信息放入其中了。

        继续看MapperProxyFactory的newInstance方法:

  protected T newInstance(MapperProxy<T> mapperProxy) 
  {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) 
  {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }
        MapperProxy就是一个代理类,使用的是jdk的动态代理

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
  {
    if (Object.class.equals(method.getDeclaringClass())) 
    {
      return method.invoke(this, args);
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }
       这里的invoke方法可以明确看出使用的是jdk的动态代理

      这样的话就会返回一个mapper的代理类,每次执行的时候,回交给MapperMethod类的execute方法

	  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 
		      {
		        Object param = method.convertArgsToSqlCommandParam(args);
		        result = sqlSession.selectOne(command.getName(), param);
		      }
		    } 
		    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;
	}
               可以看出,也就是判断一下CURD的类型,然后实际调用的还是SqlSession 的方法,在这里以selectList为例

  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      MappedStatement ms = configuration.getMappedStatement(statement);
      List<E> result = executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
      return result;
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }
          继续查找Executor的query方法,在这里使用BaseExecutor的

  public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException 
 {
    BoundSql boundSql = ms.getBoundSql(parameter);
    CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
    return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
 }
         继续查找到SimpleExecutor的doQuery,可以看到

  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(this, 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);
    handler.parameterize(stmt);
    return stmt;
  }
      可以看出实际上也就好似调用的jdbc


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值