Hibernate 6 была выпущена некоторое время назад, и я вижу, как все больше и больше команд мигрируют свои уровни персистентности или, по крайней мере, готовятся к миграции. Как это часто бывает, объем работы, необходимой для перехода на Hibernate 6, зависит от качества вашего кода и версии Hibernate, которую вы используете в настоящее время.  Для большинства приложений, использующих Hibernate 5, миграция будет относительно быстрой и простой. Но вам придется исправить и обновить некоторые вещи, если вы все еще используете более старую версию Hibernate или некоторые функции, устаревшие в Hibernate 5.  В этой статье я расскажу вам о самых важных шагах по подготовке вашего приложения к миграции и о том, что необходимо сделать при миграции вашего приложения.  Не все изменения, внесенные в Hibernate 6, являются обратно совместимыми. К счастью, с большинством из них можно разбираться до выполнения миграции. Это позволит вам внедрить необходимые изменения шаг за шагом, продолжая использовать Hibernate 5. Таким образом, вы избежите поломки вашего приложения и сможете подготовить миграцию в течение нескольких релизов или спринтов. Одним из примеров такого изменения является переход на JPA 3. Эта версия спецификации JPA не принесла никаких новых функций. Но по юридическим причинам все имена пакетов и конфигурационных параметров были переименованы из javax.persistence.* в jakarta.persistence.*. Кроме всего прочего, это изменение влияет на инструкции импорта для всех аннотаций отображения (mapping) и EntityManager и ломает все слои персистентности. Самый простой способ исправить это - использовать функцию поиска и замены в вашей IDE. Замена всех вхождений javax.persistence на jakarta.persistence должна исправить ошибки компилятора и обновить вашу конфигурацию. Hibernate 6 по умолчанию использует JPA 3, и вы можете выполнить команду поиска и замены как часть миграции. Но я рекомендую изменить зависимость вашего проекта с hibernate-core на hibernate-core-jakarta и выполнить это изменение, пока вы все еще используете Hibernate 5. Еще одним важным шагом для подготовки уровня персистентности к Hibernate 6 является замена API Criteria в Hibernate. Этот API был устаревшим с момента первого выпуска Hibernate 5, и вы, возможно, уже заменили его. Но я знаю, что для многих приложений это не так. Вы можете легко проверить, используете ли вы по-прежнему проприетарный API Criteria от Hibernate, проверив предупреждения об устаревании. Если вы найдете предупреждение об устаревании, сообщающее вам, что метод createCriteria(Class) устарел, значит, вы все еще используете старый API Hibernate и должны его заменить. К сожалению, вы больше не можете откладывать это изменение. Hibernate 6 больше не поддерживает старый, проприетарный API Criteria. API Criteria в JPA и Hibernate аналогичны. Они позволяют вам динамически создавать запрос во время выполнения. Большинство разработчиков используют его для создания запроса на основе пользовательского ввода или результата некоторых бизнес-правил. Но даже несмотря на то, что оба API имеют одинаковое название и цели, простого пути миграции не существует. Единственный выход - удалить Hibernate API Criteria из уровня персистентности Hibernate. Вам необходимо переопределить свои запросы, используя API Criteria от JPA. В зависимости от количества запросов, которые вам нужно заменить, и их сложности, это может занять некоторое время. Hibernate 5 поддерживает оба API Criteria, и я рекомендую вам заменить старые запросы один за другим до перехода на Hibernate 6. Каждый запрос индивидуален и требует разных шагов для переноса. Это затрудняет оценку того, сколько времени займет такая замена и как ее выполнить. Но некоторое время назад я написал руководство, объясняющее, как перенести наиболее часто используемые функции запросов из Hibernate в JPA Criteria API. Для всех операторов запросов, которые вы можете статически определить при реализации приложения, вы, скорее всего, используете JPQL или специфическое для Hibernate расширение HQL. При использовании HQL Hibernate может сгенерировать предложение SELECT вашего запроса на основе предложения FROM. В этом случае ваш запрос выбирает все классы сущностей, указанные в предложении FROM. К сожалению, это изменилось в Hibernate 6 для всех запросов, которые объединяют несколько классов сущностей. В Hibernate 5 запрос, объединяющий несколько классов сущностей, возвращает Object[] или List<Object[]>, содержащий все сущности, объединенные в предложении FROM. Таким образом, для оператора запроса в предыдущем фрагменте кода Hibernate сгенерировала предложение SELECT, которое ссылалось на сущности Author и Book. Сгенерированный оператор был идентичен следующему. Для того же оператора HQL Hibernate 6 генерирует только предложение SELECT, которое выбирает корневой объект вашего предложения FROM. В данном примере он выбирает только объект Author, но не объект Book. Это изменение не вызывает никаких ошибок компилятора, но создает проблемы в коде, который обрабатывает результат запроса. В лучшем случае у вас есть несколько тестовых примеров, которые обнаружат эти ошибки. Но я рекомендую добавить предложение SELECT, которое ссылается на сущность Author и Book, пока вы еще используете Hibernate 5. Это ничего не изменит для Hibernate 5, но гарантирует, что вы получите тот же результат запроса при использовании Hibernate 6, что и при использовании Hibernate 5. После реализации изменений, описанных в предыдущем разделе, ваша миграция в Hibernate 6 должна быть простой и потребовать лишь нескольких изменений конфигурации. Генерация уникальных значений первичных ключей - это первое, что вы должны проверить после миграции вашего уровня персистентности на Hibernate 6. Вам нужно внести небольшое изменение, если вы используете последовательности базы данных и не указываете последовательность для каждой сущности. Здесь показан пример сущности Author, в которой задана только стратегия генерации последовательности, но не указано, какую последовательность должен использовать Hibernate. В таких ситуациях Hibernate использует последовательность по умолчанию. В версиях 4 и 5 Hibernate использовала одну последовательность по умолчанию для всей единицы персистентности. Она называлась hibernate_sequence. Как я показал в недавней статье, Hibernate 6 изменила этот подход. По умолчанию он использует отдельную последовательность для каждого класса сущностей. Имя этой последовательности состоит из имени сущности и постфикса _SEQ. Такой подход хорош, и многие разработчики будут чувствовать себя с ним более комфортно. Но он нарушает работу существующих приложений, потому что последовательности, специфические для сущности не существуют в базе данных. У вас есть два варианта решения этой проблемы: Обновить схему базы данных, чтобы добавить новые последовательности. Добавить параметр конфигурации, чтобы указать Hibernate на использование старых последовательностей по умолчанию. При работе над миграцией я рекомендую использовать 2-й подход. Это самый быстрый и простой способ решить проблему, и вы все равно сможете добавить новые последовательности в будущем релизе. Вы можете указать Hibernate использовать старые последовательности по умолчанию, настроив свойство hibernate.id.db_structure_naming_strategy в вашем persistence.xml. Установив это значение в single, вы получите последовательности по умолчанию, используемые Hibernate <5.3. А конфигурационное значение legacy позволяет получить имена последовательностей по умолчанию, используемые Hibernate >=5.3. Я объяснил все это более подробно в своем руководстве по стратегиям именования последовательностей, используемым в Hibernate 6. Еще одно изменение, которое можно легко не заметит до тех пор, пока развертывание перенесенного слоя персистентности не даст сбой, - это отображение Instant и Duration. Когда Hibernate ввела проприетарное отображение для этих типов в версии 5, он отображал Instant на SqlType.TIMESTAMP и Duration на Types.BIGINT. Переход на Hibernate 6 изменяет это отображение. Теперь он отображает Instant на SqlType.TIMESTAMP_UTC и Duration на SqlType.INTERVAL_SECOND. Эти новые отображения кажутся более подходящими, чем старые. Поэтому хорошо, что они изменили их в Hibernate 6. Но это по-прежнему нарушает отображение таблиц в существующих приложениях. Если вы столкнетесь с этой проблемой, вы можете установить свойство конфигурации hibernate.type.preferred_instant_jdbc_type в TIMESTAMP и hibernate.type.preferred_duration_jdbc_type в BIGINT. Это два новых параметра конфигурации, введенные в Hibernate 6. Оба они помечены как инкубационные. Это означает, что они могут измениться в будущем. Поэтому я рекомендую вам использовать их во время перехода на Hibernate 6 и вскоре после этого скорректировать модель таблицы так, чтобы она соответствовала новому стандартному отображению Hibernate. Если вы читали некоторые из моих предыдущих статей о Hibernate 6, вы должны знать, что команда Hibernate переписала код, генерирующий операторы запросов. Одним из побочных эффектов этого изменения стало небольшое изменение в конфигурации ведения журнала. В Hibernate 5 необходимо активировать ведение журнала трассировки для категории org.hibernate.type.descriptor.sql, чтобы регистрировать все значения параметров привязки и значения, извлеченные из результирующего набора. В Hibernate 6 введена отдельная категория ведения журнала для значений параметров привязки (bind). Вы можете активировать ведение журнала этих значений, настроив ведение журнала трассировки для категории org.hibernate.orm.jdbc.bind. В Hibernate 6 было внесено несколько изменений, которые нарушают обратную совместимость. Не все из них требуют огромных изменений в коде вашего уровня персистентности. Возможно, будет достаточно добавить всего несколько параметров конфигурации, чтобы сохранить старое поведение. Но два изменения потребуют особого внимания. Это обновление до JPA 3 и удаление устаревшего API Criteria из Hibernate. Я рекомендую вам разобраться с обоими изменениями, пока вы все еще используете Hibernate 5. Обновление до JPA 3 требует, чтобы вы изменили имена параметров конфигурации и инструкции импорта всех классов, интерфейсов и аннотаций, определенных спецификацией. Но не волнуйтесь. Обычно это звучит хуже, чем есть на самом деле. Я перенес несколько проектов, выполнив простую операцию поиска и замены в своей IDE. Обычно это делалось за несколько минут. Удаление устаревшего API Criteria в Hibernate вызовет более серьезные проблемы. Вам нужно будет переписать все запросы, которые используют старый API. Я рекомендую вам сделать это, пока вы еще используете Hibernate 5. Он по-прежнему поддерживает старый API Criteria от Hibernate и API Criteria от JPA. Таким образом, вы сможете заменять один запрос за другим, не нарушая работу вашего приложения.