Рубрики
Без рубрики

9 Советов по повышению производительности при использовании MySQL с JPA и гибернацией

Автор оригинала: Vlad Mihalcea.

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

В этой статье мы рассмотрим, что вы можете сделать для повышения производительности при использовании MySQL с JPA и Hibernate.

Каждая сущность должна иметь идентификатор, который однозначно идентифицирует запись таблицы, связанную с этой сущностью. JPA и Hibernate позволяют автоматически генерировать идентификаторы сущностей на основе трех различных стратегий:

  • ИДЕНТИЧНОСТЬ
  • ПОСЛЕДОВАТЕЛЬНОСТЬ
  • СТОЛ

Как я объяснил в этой статье , стратегия идентификатора ТАБЛИЦЫ не масштабируется при увеличении числа подключений к базе данных. Более того, даже для одного подключения к базе данных время отклика на генерацию идентификатора в 10 раз больше, чем при использовании ИДЕНТИФИКАТОРА или ПОСЛЕДОВАТЕЛЬНОСТИ.

Если вы используете АВТОМАТИЧЕСКИЙ Тип генерации :

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

Hibernate 5 вернется к использованию генератора ТАБЛИЦ, что плохо сказывается на производительности.

Как я объяснил в этой статье , вы можете легко устранить эту проблему с помощью следующего сопоставления:

@Id
@GeneratedValue(strategy= GenerationType.AUTO, generator="native")
@GenericGenerator(name = "native", strategy = "native")
private Long id;

Собственный генератор выберет ИДЕНТИФИКАТОР вместо ТАБЛИЦЫ.

Ни MySQL 5.7, ни 8.0 не поддерживают объекты ПОСЛЕДОВАТЕЛЬНОСТИ. Вам нужно использовать УДОСТОВЕРЕНИЕ личности. Однако, как я объяснил в этой статье , генератор удостоверений предотвращает использование пакетных вставок JDBC в режиме гибернации.

Пакетные обновления и удаления JDBC не затрагиваются. Только инструкции INSERT не могут быть автоматически сгруппированы Hibernate, потому что к моменту сброса контекста сохранения инструкции INSERT уже были выполнены, так что Hibernate знает, какой идентификатор сущности назначить сохраняемым сущностям.

Если вы хотите устранить эту проблему, вам необходимо выполнить пакетную вставку JDBC с помощью другой платформы, например jOOQ .

MySQL и MariaDB, как известно, работают очень медленно, когда приходится отбрасывать схему базы данных и воссоздавать ее каждый раз, когда готовится новый интеграционный тест. Однако вы можете легко решить эту проблему с помощью Docker и tmpfs.

Как я объяснял в этой статье , сопоставляя папку данных в памяти, интеграционные тесты будут выполняться почти так же быстро, как с базой данных в памяти, такой как H2 или HSQLDB.

Даже когда вы используете СУБД, часто возникает необходимость в хранении неструктурированных данных:

  • данные поступают от клиента в формате JSON, которые необходимо проанализировать и вставить в нашу систему.
  • результаты обработки изображений, которые можно кэшировать для сохранения их повторной обработки

Хотя изначально не поддерживается, вы можете легко сопоставить объект Java со столбцом JSON . Вы даже можете сопоставить тип столбца JSON с JSON-кодом Джексона .

Более того, вам даже не нужно писать эти пользовательские типы, вы можете просто взять их из Maven Central:


    com.vladmihalcea
    hibernate-types-55
    ${hibernate-types.version}

Круто, правда?

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

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

Потоковая передача SQL имеет смысл для двухуровневых приложений. Если вы хотите выполнить потоковую передачу набора результатов, вы также должны обратить внимание на драйвер JDBC. В MySQL для использования курсора базы данных у вас есть два варианта:

  • либо вы задаете свойству FetchSize оператора JDBC значение Integer.МИНИМАЛЬНОЕ ЗНАЧЕНИЕ ,
  • или вам нужно установить для свойства useCursorFetch connection значение true , а затем вы можете установить для свойства JDBC Оператор |/размер выборки положительное целое значение

Однако для веб-приложений гораздо более подходит разбиение на страницы. В JPA 2.2 даже предусмотрена поддержка потоковых методов Java 1.8 , но план выполнения может быть не таким эффективным, как при использовании разбиения на страницы на уровне SQL.

Хотя вы могли бы это сделать, поскольку Hibernate по умолчанию использует Подготовленные операторы , все операторы выполняются следующим образом:

На самом деле они выполняются скорее так:

Как я объяснил в этой статье , если вы не установите свойство useServerPrepStmts Драйвер JDBC MySQL, Подготовленные инструкции будут эмулироваться на уровне драйвера JDBC, чтобы сэкономить одну дополнительную базу данных в оба конца.

В реляционной базе данных каждая инструкция выполняется в рамках данной транзакции базы данных . Поэтому транзакции не являются необязательными.

Однако вы всегда должны завершать текущую текущую транзакцию либо путем фиксации, либо путем отката. Забывание завершить транзакции может привести к тому, что блокировки будут удерживаться в течение очень долгого времени, а также к тому, что процесс очистки MVCC не сможет восстановить старые кортежи или записи индекса, которые больше не нужны .

В программировании есть две очень сложные вещи:

  • обработка кодировок
  • передача даты/времени по нескольким часовым поясам

Для решения второй проблемы лучше сохранить все метки времени в часовом поясе UTC . Однако до MySQL Connector/J 8.0 вам также необходимо было установить для свойства конфигурации драйвера useLegacyDatetimeCode JDBC значение false . Начиная с MySQL Connector/J 8.0, вам не нужно предоставлять это свойство.

Как вы можете видеть, есть много вещей, которые следует иметь в виду при использовании MySQL с JPA и Hibernate. Поскольку MySQL является одной из наиболее развернутых СУБД, используемой подавляющим большинством веб-приложений, очень полезно знать все эти советы и настроить уровень доступа к данным, чтобы извлечь из этого максимальную пользу.