Глава 27. Вопросы по переносимоси баз данных

Оглавление
  1. 27.1. Основы переносимости
  2. 27.2. Диалект
  3. 27.3. Разрешение диалекта
  4. 27.4. Генерация идентификаторов
  5. 27.5. Функции базы данных

27.1. Основы переносимости

Одной из "продающих точек" Hibernate (и объектно-реляционногоl отображения в целом) является понятие переносимости базы данных. Это может означать, что внутренний ИТ-пользователь может перейти от одного поставщика базы данных к другому, или это может означать, что их инфраструктура или развертываемое приложение, использующее Hibernate, одновременно нацеливаются их пользователями на несколько продуктов баз данных. Независимо от точного сценария, основная идея заключается в том, что вы хотите, чтобы Hibernate помогал вам работать с любым количеством баз данных без изменений вашего кода и в идеале без каких-либо изменений в метаданных сопоставлений.

27.2. Диалект

Первой линией переносимости для Hibernate является диалект, который является специализацией договора org.hibernate.dialect.Dialect. Диалект инкапсулирует все различия в том, как Hibernate должен связываться с конкретной базой данных, для выполнения некоторой задачи, например, получения значение последовательности или структурирования запроса SELECT. Hibernate объединяет широкий спектр диалектов для многих из самых популярных баз данных. Если вы обнаружите, что диалект вашей конкретная базы данных не входит в их число, писать его не сложно.

27.3. Разрешение диалекта

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

Начиная с версии 3.2, Hibernate представил понятие автоматического обнаружения диалекта для использования на основе java.sql.DatabaseMetaData, полученной из java.sql.Connection к этой базе данных. Намного лучше ожидать, что эта резолюция ограничена базами данных, о которых Hibernate знает заранее, и которые не могут быть конфигурируемыми или переопределяемыми.

Начиная с версии 3.3, Hibernate имеет более мощный способ автоматического определения того, какой диалект должен использоваться, полагаясь на ряд делегатов, которые реализуют org.hibernate.dialect.resolver.DialectResolver, который определяет только один метод:

public Dialect resolveDialect(DatabaseMetaData metaData) throws JDBCConnectionException

Основной контракт заключается в том, что если распознаватель «понимает» метаданные базы данных, то он возвращает соответствующий диалект. Иначе он возвращает значение null и процесс переходит к следующему преобразователю. В сигнатуре также указывается, что может быть выброшено org.hibernate.exception.JDBCConnectionException. Исключение JDBCConnectionException интерпретируется как подразумевающее проблему «непереходного (non transient)» (или невосстанавливаемого) соединения и используется для указания немедленной остановки попыток разрешения. Все остальные исключения приводят к предупреждению и продолжают переход к следующему распознавателю.

Замечательная часть этих распознавателей заключается в том, что пользователи могут также регистрировать свои собственные настраиваемые распознаватели, которые будут обрабатываться перед распознавателями Hibernate . Это может быть полезно в нескольких разных ситуациях: позволяет легко интегрировать для автоматического обнаружения диалектов помимо тех, которые поставляются с самим Hibernate; позволяет указать использование пользовательского диалекта при распознавании определенной базы данных; и т. д. Чтобы зарегистрировать один или несколько преобразователей, просто укажите их (разделённые запятыми, табуляциями или пробелами), используя настройку конфигурации «hibernate.dialect_resolvers» (см. константу DIALECT_RESOLVERS на org.hibernate.cfg.Environment).

27.4. Генерация идентификаторов

При рассмотрении переносимости между базами данных другим важным решением является выбор стратагии генерации идентификатора, которую вы хотите использовать. Первоначально Hibernate предоставил для этого собственный генератор, который был предназначен для выбора между стратегиями sequence, identity или table в зависимости от возможностей базовой базы данных. Минусом этого подхода является то, что некоторые базы данных поддерживают генерацию identity, а некоторые нет. Identity генерация основывается на определении SQL столбца IDENTITY (или auto-increment) для управления значением идентификатора; это то, что известно как стратегия генерации после вставки, потому что вставка должна действительно произойти, прежде чем мы сможем узнать значение идентификатора. Поскольку Hibernate полагается на это значение идентификатора для однозначной привязки сущностей в контексте персистентности, он должен затем немедленно сделать вставку, когда пользователи запрашивают, чтобы entitiy был связан с сессией (например, через save()), независимо от текущей транзакционной семантики.

Заметка

Hibernate был слегка изменен, как только это стало понятным, так что вставка задерживается в тех случаях, когда это возможно.

Изложенная проблема заключается в том, что фактическая семантика самого приложения изменяется в этих случаях.

Начиная с версии 3.2.3, Hibernate поставляется с набором улучшенных генераторов идентификаторов, нацеленных на переносимость в совершенно другом ключе.

Заметка

Существуют, в частности, два дополнительных улучшенных генератора:

Идея этих генераторов заключается в переносе фактической семантики генерации значения идентификатора в разные базы данных. Например, org.hibernate.id.enhanced.SequenceStyleGenerator имитирует поведение последовательности в базах данных, которые не поддерживают последовательности, используя таблицу.

27.5. Функции базы данных

Внимание

Это область в Hibernate, нуждающаяся в улучшении. Что касается проблем с переносимостью, эта обработка функций в настоящее время очень хорошо работает с HQL; однако она совершенно отсутствует во всех других аспектах.

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

Важно

Технически эта регистрация функции осуществляется через класс org.hibernate.dialect.function.SQLFunctionRegistry, который предназначен для предоставления пользователям возможности определять собственные функции без необходимости предоставления собственного диалекта. Это конкретное поведение еще не завершено.

Это похоже на то, что пользователи могут программно регистрировать функции с org.hibernate.cfg.Configuration, и эти функции будут распознаны для использования в HQL.

Этот раздел создатели Hibernate планируют завершить позднее.