Hibernate.orgCommunity Documentation

Capítulo 28. Consideraciones de la portabilidad de la base de datos

28.1. Aspectos básicos de la portabilidad
28.2. Dialecto
28.3. Resolución del dialecto
28.4. Generación del identificador
28.5. Funciones de la base de datos
28.6. Mapeos de tipo

Uno de los aspectos que más vende de Hibernate (y realmente del mapeo objeto/relacional en sí) es la noción de portabilidad de la base de datos. Podría ser el caso de un administrador de sistemas migrando de una base de datos de un vendedor a otro, o podría ser un marco de trabajo o una aplicación desplegable consumiendo Hibernate para que apunte simultáneamente a múltiples productos de bases de datos. Sin importar el escenario exacto, la idea básica es que quiere que Hibernate le ayude a ejecutar frente a cualquier número de bases de datos sin cambiar el código e idealmente sin cambiar los metadatos de mapeo.

La primera línea de portabilidad para Hibernate es el dialecto, el cual es una especialización del contrato org.hibernate.dialect.Dialect. Un dialecto encapsula todas las diferencias en la manera en que Hibernate debe comunicarse con una base de datos en particular para lograr alguna tarea como el obtener un valor de secuencia o el estructurar una petición SELECT. Hibernate reune un gran rango de dialectos para muchas de las bases de datos más populares. Si encuentra que su base de datos en particular no se encuentra entre estos, no es demasiado dificil es escribir el propio.

Originalmente, Hibernate siempre requería que los usuarios especificaran qué dialecto utilizar. En el caso de aquellos usuarios que buscaban apuntar a múltiples bases de datos de manera simultánea con su construcción eso representaba un problema. Generalmente esto requería que los usuarios configuraran el dialecto de Hibernate o que definieran su propio método para establecer ese valor.

Empezando con la versión 3.2, Hibernate introdujo la noción de detectar automáticamente el dialecto a utilizar con base en los java.sql.DatabaseMetaData que se obtuvieron de una java.sql.Connection a esa base de datos. Esto era mucho mejor pero esta resolución estaba limitada a las bases de datos que Hibernate conoce por adelantado y de ninguna manera era configurable ni se podía sobreescribir.

Starting with version 3.3, Hibernate has a fare more powerful way to automatically determine which dialect to should be used by relying on a series of delegates which implement the org.hibernate.dialect.resolver.DialectResolver which defines only a single method:

public Dialect resolveDialect(DatabaseMetaData metaData) throws JDBCConnectionException

The basic contract here is that if the resolver 'understands' the given database metadata then it returns the corresponding Dialect; if not it returns null and the process continues to the next resolver. The signature also identifies org.hibernate.exception.JDBCConnectionException as possibly being thrown. A JDBCConnectionException here is interpreted to imply a "non transient" (aka non-recoverable) connection problem and is used to indicate an immediate stop to resolution attempts. All other exceptions result in a warning and continuing on to the next resolver.

La parte divertida de estos resolvedores es que los usuarios también pueden registrar sus propios resolvedores personalizados, los cuales se procesarán antes de los incluídos en Hibernate. Esto puede llegar a ser útil en un número de situaciones diferentes: permite una fácil integración para la auto-detección de dialectos más allá de los que se envían junto con Hibernate; le permite especificar el uso de un dialecto personalizado cuando se reconoce una base de datos en particular; etc. Para registrar uno o más resolvedores, simplemente especifiquelos (separados por comas o espacios) usando la configuración 'hibernate.dialect_resolvers' (consulte la constante DIALECT_RESOLVERS en org.hibernate.cfg.Environment).

When considering portability between databases, another important decision is selecting the identifier generation stratagy you want to use. Originally Hibernate provided the native generator for this purpose, which was intended to select between a sequence, identity, or table strategy depending on the capability of the underlying database. However, an insidious implication of this approach comes about when targtetting some databases which support identity generation and some which do not. identity generation relies on the SQL definition of an IDENTITY (or auto-increment) column to manage the identifier value; it is what is known as a post-insert generation strategy becauase the insert must actually happen before we can know the identifier value. Because Hibernate relies on this identifier value to uniquely reference entities within a persistence context it must then issue the insert immediately when the users requests the entitiy be associated with the session (like via save() e.g.) regardless of current transactional semantics.

The underlying issue is that the actual semanctics of the application itself changes in these cases.

Starting with version 3.2.3, Hibernate comes with a set of enhanced identifier generators targetting portability in a much different way.

Nota

There are specifically 2 bundled enhancedgenerators:

  • org.hibernate.id.enhanced.SequenceStyleGenerator

  • org.hibernate.id.enhanced.TableGenerator

The idea behind these generators is to port the actual semantics of the identifer value generation to the different databases. For example, the org.hibernate.id.enhanced.SequenceStyleGenerator mimics the behavior of a sequence on databases which do not support sequences by using a table.

Los usuarios pueden referenciar las funciones de SQL de muchas maneras. Sin embargo, no todas las bases de datos soportan el mismo grupo de funciones. Hibernate proporciona una manera de mapear un nombre de una función lógica a un delegado, el cual sabe cómo entregar esa función en particular, tal vez incluso usando una llamada de función física totalmente diferente.

Esta sección se completará en un futuro cercano...