Hibernate.orgCommunity Documentation
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.
Hibernate was changed slightly once the implication of this was better understood so that the insert is delayed in cases where that is feasible.
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.
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.
Esta es un área en la que Hibernate necesita mejorar. En términos de qué tan portatil puede ser, esta función que se maneja actualmente trabaja bastante bien desde HQL; sin embargo, en otros aspectos le falta mucho.
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.
Técnicamente este registro de función se maneja por medio de la clase org.hibernate.dialect.function.SQLFunctionRegistry
, la cual tiene el propósito de permitirle a los usuarios el proporcionar definiciones de funciones personalizadas sin tener que brindar un dialecto personalizado. Este comportamiento especifico todavía no está del todo completo.
De cierta manera está implementado para que los usuarios puedan registrar programáticamente las funciones con la org.hibernate.cfg.Configuration
y aquellas funciones serán reconocidas por HQL.
Copyright © 2004 Red Hat, Inc.