Объясните MyBatis простыми словами: анализ MyBatis и принцип работы

задняя часть база данных MyBatis SQL

Эта статья является кратким изложением книги «MyBatis простыми словами: технические принципы и практика».

В последней статье были представлены основы отражения и динамического прокси, в основном для того, чтобы подготовить почву для этой статьи. Отражение значительно улучшает конфигурацию и гибкость и может задавать параметры для многих конфигураций. Динамический прокси может создавать прокси-объекты во время выполнения и выполнять некоторую специальную обработку.

Индекс статьи:

  1. Введение в JDBC и MyBatis
  2. Все конфигурации MyBatis
  3. "Маппер" все понимают
  4. Основы отражения и динамических прокси
  5. Плагин MyBatis и процесс разработки

В этой статье будет представлен анализ и принцип работы MyBatis. В следующей статье будут представлены плагины и приложения, чтобы лучше писать плагины. Благодаря введению в эту статью вы узнаете:

  • Создайте процесс SqlSessionFactory.
  • Динамические прокси для картографов
  • 4 объекта SqlSession
  • процесс выполнения sql

SqlSessionFactory и SqlSession являются основными компонентами MyBatis, в статьеВведение в JDBC и MyBatisподробно описаны.

Создайте процесс SqlSessionFactory.

Строительство в основном делится на 2 этапа:

  • Проанализируйте сконфигурированный XML-файл с помощью XMLConfigBuilder и прочитайте параметры конфигурации, включая XML-файл базовой конфигурации и XML-файл преобразователя;
  • Используйте объект Configuration для создания SqlSessionFactory.SqlSessionFactory — это интерфейс, предоставляющий класс реализации по умолчанию DefaultSqlSessionFactory.

Грубо говоря, это разобрать все наши конфигурации на объекты Configuration, через которые нужную конфигурацию можно получить на протяжении всего жизненного цикла.

Поскольку плагину необходимо часто обращаться к внутренним компонентам картографа, мы сосредоточимся на этой части, чтобы понять объекты, абстрагированные от этой конфигурации:

MappedStatement

Он сохраняет узел преобразователя (выбрать|вставить|удалить|обновить), включая настроенный SQL, идентификатор SQL, информацию о кеше, карту результатов, тип параметра, тип результата и другое важное содержимое конфигурации.

Он включает в себя больше объектов, как правило, не изменяйте его.

SqlSource

Является атрибутом MappedStatement, его основная функция — сборка SQL по параметрам и другим правилам, он тоже очень сложен, и его вообще не нужно модифицировать.

BoundSql

Для параметров и SQL это в основном отражается на объекте класса BoundSql.В плагине через него получают текущий работающий SQL, параметры и правила параметров, и вносятся соответствующие модификации для удовлетворения особых требований.

BoundSql предоставляет 3 основных свойства: parameterObject, parameterMappings и sql, которые будут представлены отдельно ниже.

parameterObject — это сам параметр, и вы можете передавать простые объекты, POJO, карты или параметры, аннотированные @Param:

  • Передача простого объекта (int, float, String и т. д.) приведет к преобразованию параметра в соответствующий класс, например, int будет преобразован в Integer;
  • Если передается POJO или Map, paramterObject совпадает с входящим POJO или Map;
  • Если передается несколько параметров без аннотации @Param, parameterObject представляет собой объект Map, аналогичный этой форме {"1":p1 , "2":p2 , "3":p3 ... "param1 " :p1 , "param2":p2 , "param3",p3 ...}, поэтому вы можете использовать #{param1} или #{1} для ссылки на первый параметр при записи;
  • При передаче нескольких параметров имеется аннотация @Param, аналогичная аннотации без аннотации, но заменяющая ключ серийного номера на имя, указанное в @Param;

parameterMappings, это список, элемент представляет собой объект ParameterMapping, этот объект будет описывать ссылку на параметр в sql, включая имя, выражение, javaType, jdbcType, typeHandler и другую информацию.

sql, это sql, написанный в маппере.

С объектом Configuration создание SqlSessionFactory выполняется просто:

sqlSessionFactory = new SqlSessionFactoryBuilder().bulid(inputStream);

Запущенный процесс SqlSession

Динамические прокси для картографов

Сопоставление Mapper реализуется через динамические прокси, используя динамические прокси JDK для возврата прокси-объекта для доступа вызывающей стороны.

Сначала взгляните на класс, реализующий интерфейс InvocationHandler, который является ключом к выполнению этого прокси-метода.Как видите, Mapper — это интерфейс, который генерирует объект MapperMethod и вызывает метод execute.

public class MapperProxy<T> implements InvocationHandler, Serializable {
  
  .....
  
  @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);
  }
}

Глядя на следующий код, MapperMethod принимает командный режим и выполняет различную обработку в соответствии с различными операциями SQL.

public class MapperMethod {
  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;
        
        ......
        
      }
    }
  }

Наконец, посмотрите на метод создания прокси-класса, который создается с помощью динамического прокси-сервера JDK.

public class MapperProxyFactory<T> {

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

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

}

Обобщая процесс вызова маппера, возвращаемый объект Mapper является прокси-объектом.При вызове одного из его методов он фактически вызывает метод MapperProxy#invoke, а пространство имен XML-файла маппера соответствует полному пути интерфейса. , сможет выполнить привязку в соответствии с полным путем и именем метода, найти sql и, наконец, использовать метод интерфейса SqlSession, чтобы позволить ему выполнить запрос.

Четыре объекта в SqlSession

Согласно приведенному выше анализу, сопоставитель представляет собой динамический прокси-объект, который входит в метод выполнения MapperMethod. Он входит в методы удаления, обновления, вставки, выбора и другие методы SqlSession после простого суждения. Как выполнять эти методы, является содержанием для быть представлено ниже.

Процесс выполнения Mapper осуществляется через Executor, StatementHandler, ParameterHandler и ResultHandler для завершения операций с базой данных и возврата результатов.Понимание их является ключом к написанию плагинов:

  • Исполнитель: исполнитель, который единообразно планирует три других объекта для выполнения соответствующего SQL;
  • StatementHandler: используйте оператор базы данных для выполнения операций;
  • ParameterHandler: используется для SQL-обработки параметров;
  • ResultHandler: инкапсулировать и вернуть окончательный набор данных;

В MyBatis есть три исполнителя:

  • SIMPLE: простой исполнитель, исполнитель по умолчанию;
  • REUSE: выполняет повторно используемый подготовленный оператор;
  • BATCH: выполнение повторно используемых операторов и пакетных обновлений для исполнителей, специфичных для пакетов;

Возьмите SimpleExecutor в качестве примера, чтобы проиллюстрировать процесс выполнения.

public class SimpleExecutor extends BaseExecutor {

  /**
  * 执行查询操作
  */
  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);
    }
  }
  
  /**
  * 初始化StatementHandler
  */
  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    Connection connection = getConnection(statementLog);
    stmt = handler.prepare(connection);
    handler.parameterize(stmt);
    return stmt;
  }
  
  /**
  * 执行查询
  */
  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    String sql = boundSql.getSql();
    statement.execute(sql);
    return resultSetHandler.<E>handleResultSets(statement);
  }
}

Видно, что он будет делегирован обработчику сеанса StatementHandler для обработки.Это интерфейс.Фактически создается объект RoutingStatementHandler, но он не является реальным служебным объектом.Выполняется путем нахождения соответствующего StatementHandler через режим адаптера. . В MyBatis, StatementHandler и Executor делятся на три типа: SimpleStatementHandler, PreparedStatementHandler и CallableStatementHandler.

Executor сначала вызовет метод подготовки статеменсандлера, чтобы предварительно скомпилировать оператор SQL и установить некоторые основные рабочие параметры. Затем вызовите метод parameterize(), чтобы позволить ParameterHandler установить параметры, завершить предварительную компиляцию, выполнить запрос и инкапсулировать результат с помощью ResultHandler и вернуть его вызывающей стороне.

Обработчики параметров и обработчики результатов относительно просты и не будут здесь рассматриваться.

В следующей статье будет представлен подключаемый модуль и его применение, в основном в процессе выполнения sql, на основе четырех основных объектов для расширения.

Плагин MyBatis и процесс разработки

Добро пожаловать, чтобы отсканировать QR-код ниже и подписаться на мою личную общедоступную учетную запись WeChat~

情情说