Configuración
Debido a que Hibernate está diseñado para operar en muchos entornos
diferentes, hay un gran número de parámetros de configuración.
Afortunadamente, la mayoría tiene valores por defecto sensibles e Hibernate
se distribuye con un fichero hibernate.properties de ejemplo en
etc/ que muestra las diversas opciones. Tan sólo pon el
fichero de ejemplo en tu classpath y personalízalo.
Configuración programática
Una instancia de org.hibernate.cfg.Configuration
representa un conjunto entero de mapeos de los tipos Java de una aplicación
a una base de datos SQL. La Configuration es usada para
construir una SessionFactory (inmutable). Los mapeos se
compilan de varios ficheros de mapeo XML.
Puedes obtener una instancia de Configuration instanciándola
directamente y especificando documentos de mapeo XML. Si los ficheros de mapeo
están en el classpath, usa addResource():
Una forma alternativa (a veces mejor) es especificar la clase mapeada,
y dejar que Hibernate encuentre el documento de mapeo por ti:
Entonces Hibernate buscará ficheros de mapeo llamados
/org/hibernate/auction/Item.hbm.xml y
/org/hibernate/auction/Bid.hbm.xml en el classpath.
Este enfoque elimina cualquier nombre de fichero en el código.
Una Configuration también te permite especificar
propiedades de configuración:
Esta no es la única forma de pasar propiedades de configuración
a Hibernate. La diversas opciones incluyen:
Pasar una instancia de java.util.Properties a
Configuration.setProperties().
Colocar hibernate.properties en un directorio
raíz del classpath.
Establecer propiedades System
usando java -Dproperty=value.
Incluir elementos <property>
en hibernate.cfg.xml (discutido luego).
hibernate.properties es el enfoque más fácil
si quieres comenzar rápido.
La Configuration está concebida como un objeto
de tiempo de arranque, para ser descartado una vez que una
SessionFactory es creada.
Obteniendo una SessionFactory
Cuando todos los mapeos han sido parseados por la Configuration,
la aplicación debe obtener una fábrica de instancias de Session.
Esta fábrica está concebida para ser compartida por todas las hebras de
aplicación:
Hibernate permite que tu aplicación instancie más de una
SessionFactory. Esto es útil si estás usando
más de una base de datos.
Conexiones JDBC
Usualmente, quieres que la SessionFactory cree y almacene
en pool conexiones JDBC para ti. Si adoptas este enfoque, abrir una Session
es tan simple como:
En cuanto hagas algo que requiera acceso a la base de datos, se obtendrá una
conexión JDBC del pool.
Para que esto funcione, necesitamos pasar algunas propiedades de conexión
JDBC a Hibernate. Todos los nombres de propiedades y su semántica
están definidas en la clase org.hibernate.cfg.Environment.
Describiremos ahora las configuraciones más importantes para la conexión
JDBC.
Hibernate obtendrá (y tendrá en pool) conexiones usando
java.sql.DriverManager si configuras las siguientes propiedades:
Propiedades JDBC de Hibernate
Nombre de propiedad
Propósito
hibernate.connection.driver_class
clase del driver jdbc
hibernate.connection.url
URL de jdbc
hibernate.connection.username
usuario de base de datos
hibernate.connection.password
contraseña del usuario de base de datos
hibernate.connection.pool_size
número máximo de conexiones manejadas por pooling
El algoritmo de pooling de conexiones propio de Hibernate es sin embargo
algo rudimentario. Está concebido para ayudarte a comenzar y
no está concebido para usar en un sistema de producción
ni siquiera para pruebas de rendimiento. Debes usar un pool de terceros para
un mejor rendimiento y estabilidad. Sólo remplaza la propiedad
hibernate.connection.pool_size con configuraciones
específicas del pool de conexiones. Esto desactivará el pool
interno de Hibernate. Por ejemplo, podrías querer usar C3P0.
C3P0 es un pool de conexiones JDBC de código abierto distribuido
junto a Hibernate en el directorio lib.
Hibernate usará su C3P0ConnectionProvider
para pooling de conexiones si estableces propiedades hibernate.c3p0.*.
Si quieres usar Proxool refiérete al hibernate.properties
empaquetado y al sitio web de Hibernate para más información.
Aquí hay un fichero hibernate.properties de ejemplo para C3P0:
Para su uso en un servidor de aplicaciones, casi siempre debes configurar
Hibernate para que obtenga conexiones de un Datasource
del servidor de aplicaciones registrado en JNDI. Necesitarás establecer
al menos una de las siguientes propiedades:
Propiedades de Datasource de Hibernate
Nombre de propiedad
Propósito
hibernate.connection.datasource
nombre del datasource JNDI
hibernate.jndi.url
URL del provedor JNDI (optional)
hibernate.jndi.class
clase de la InitialContextFactory de JNDI (opcional)
hibernate.connection.username
usuario de base de datos (opcional)
hibernate.connection.password
contraseña del usuario de base de datos (opcional)
He aquí un fichero hibernate.properties de ejemplo
para un un datasource JNDI provisto por un servidor de aplicaciones.
Las conexiones JDBC obtenidas de un datasource JNDI participarán automáticamente
en las transacciones del servidor de aplicaciones manejadas por contenedor.
Pueden darse propiedades de conexión arbitrarias anteponiendo
"hibernate.connnection" al nombre de propiedad.
Por ejemplo, puedes especificar un charSet usando
hibernate.connection.charSet.
Puedes definir tu propia estrategia de plugin para obtener conexiones JDBC implementando
la interface org.hibernate.connection.ConnectionProvider. Puedes
seleccionar una implementación personalizada estableciendo
hibernate.connection.provider_class.
Parámetros de configuración opcionales
Hay un número de otras propiedades que controlan el comportamiento
de Hibernate en tiempo de ejecución. Todas son opcionales y tienen
valores por defecto razonables.
Advertencia: algunas de estas propiedades son de "nivel-de-sistema"
solamente.. Las propiedades a nivel de sistema sólo pueden ser
establecidas por medio de java -Dproperty=value o
hibernate.properties. No pueden
establecerse por medio de las otras técnicas arriba descritas.
Propiedades de Configuración de Hibernate
Nombre de propiedad
Propósito
hibernate.dialect
El nombre de clase de un Dialect
de Hibernate que permite a Hibernate generar SQL optimizado
para una base de datos relacional en particular.
ej.
full.classname.of.Dialect
hibernate.show_sql
Escribe todas las sentencias SQL a la consola.
ej.
true | false
hibernate.default_schema
Cualifica, en el SQL generado, los nombres de tabla sin cualificar
con el esquema/tablespace dado.
ej.
SCHEMA_NAME
hibernate.default_catalog
Cualifica, en el SQL generado, los nombres de tabla sin cualificar
con el catálogo dado.
ej.
CATALOG_NAME
hibernate.session_factory_name
La SessionFactory será
ligada a este nombre en JNDI automáticamente
después de ser creada.
ej.
jndi/composite/name
hibernate.max_fetch_depth
Establece una "profundidad" máxima del
árbol de recuperación por outer join
para asociaciones de un extremo solo (uno-a-uno, muchos-a-uno).
Un 0 deshabilita la recuperación
por outer join por defecto.
ej.
valores recomendados entre 0 y
3
hibernate.default_batch_fetch_size
Establece un tamaño por defecto para la recuperación
en lote de asociaciones de Hibernate.
ej.
valores recomendados 4, 8,
16
hibernate.default_entity_mode
Establece un modo por defecto de representación de
entidades para todas las sesiones abiertas por esta
SessionFactory
dynamic-map, dom4j,
pojo
hibernate.order_updates
Fuerza a Hibernate a ordenar las actualizaciones SQL
por el valor de la clave primaria de los items a actualizar.
Esto resultará en menos bloqueos muertos de transacción
en sistemas altamente concurrentes.
ej.
true | false
hibernate.generate_statistics
De habilitarse, Hibernate colectará estadísticas
útiles para la afinación de rendimiento.
ej.
true | false
hibernate.use_identifer_rollback
De habilitarse, las propiedades identificadoras
generadas serán reseteadas a valores por
defecto cuando los objetos sean borrados.
ej.
true | false
hibernate.use_sql_comments
De activarse, Hibernate generará comentarios dentro del SQL,
para una más fácil depuración, por defecto a
false.
ej.
true | false
Propiedades de JDBC y Conexiones de Hibernate
Nombre de propiedad
Propoósito
hibernate.jdbc.fetch_size
Un valor distinto de cero que determina el tamaño
de recuperación de JDBC (llama a
Statement.setFetchSize()).
hibernate.jdbc.batch_size
Un valor distinto de cero habilita el uso de actualizaciones
en lote de JDBC2 por Hibernate.
ej.
valores recomendados entre 5 y 30
hibernate.jdbc.batch_versioned_data
Establece esta propiedad a true si tu driver JDBC
devuelve cuentas correctas de filas desde executeBatch()
(usualmente es seguro activar esta opción). Hibernate usará
DML en lote para versionar automáticamente los datos.
Por defecto a false.
ej.
true | false
hibernate.jdbc.factory_class
Selecciona un Batcher personalizado.
La mayoría de las aplicaciones no necesitarán
esta propiedad de configuración.
ej.
classname.of.Batcher
hibernate.jdbc.use_scrollable_resultset
Habilita el uso de resultados scrollables de JDBC2 por Hibernate.
Esta propiedad sólo es necesaria cuando se usan conexiones
JDBC provistas por el usuario, en caso contrario Hibernate usa los
metadatos de conexión.
ej.
true | false
hibernate.jdbc.use_streams_for_binary
Usa flujos (streams) al escribir/leer tipos
binary o serializable
a/desde JDBC (propiedad a nivel de sistema).
ej.
true | false
hibernate.jdbc.use_get_generated_keys
Habilita el uso de PreparedStatement.getGeneratedKeys()
de JDBC3 para traer claves generadas nativamente después de insertar.
Requiere un driver JDBC3+ y un JRE1.4+. Establécela a false si tu
driver tiene problemas con los generadores de identificador de Hibernate.
Por defecto, se intenta determinar las capacidades del driver usando los
metadatos de conexión.
ej.
true|false
hibernate.connection.provider_class
EL nombre de clase de un ConnectionProvider personalizado
que provea conexiones JDBC a Hibernate.
ej.
classname.of.ConnectionProvider
hibernate.connection.isolation
Establece el nivel de aislamiento de transacción JDBC.
Comprueba java.sql.Connection para valores
significativos pero observa que la mayoría de las bases de
datos no soportan todos los niveles de aislamiento.
eg.
1, 2, 4, 8
hibernate.connection.autocommit
Habilita compromiso automático (autocommit) para
las conexiones JDBC en pool (no recomendado).
ej.
true | false
hibernate.connection.release_mode
Especifica cuándo Hibernate debe liberar las conexiones JDBC.
Por defecto, una conexión JDBC es retenida hasta que la sesión
es cerrada explícitamente o desconectada. Para un datasource JTA
del servidor de aplicaciones, debes usar after_statement
para liberar agresivamente las conexiones después de cada llamada
JDBC. Para una conexión no JTA, frecuentemente tiene sentido liberar
la conexión al final de cada transacción, usando
after_transaction. auto eligirá
after_statement para las estrategias JTA o CMT
de transacción y after_transaction para la
estrategia JDBC de transacción.
ej.
on_close (por defecto)| after_transaction |
after_statement | auto
hibernate.connection.<propertyName>
Pasa la propiedad JDBC propertyName
a DriverManager.getConnection().
hibernate.jndi.<propertyName>
Pasa la propiedad propertyName
a InitialContextFactory de JNDI.
Propiedades de Caché de Hibernate
Nombre de propiedad
Propósito
hibernate.cache.provider_class
El nombre de clase de un CacheProvider personalizado.
ej.
classname.of.CacheProvider
hibernate.cache.use_minimal_puts
Optimiza la operación del caché de segundo nivel
para minimizar escrituras, al costo de lecturas más frecuentes.
Esto es más útil para cachés en cluster y,
en Hibernate3, está habilitado por defecto para implementaciones
de caché en cluster.
ej.
true|false
hibernate.cache.use_query_cache
Habilita el caché de lectura, consultas individuales todavía
tienen que ponerse cachables.
ej.
true|false
hibernate.cache.use_second_level_cache
Puede ser usado para deshabilitar completamente el caché
de segundo nivel, que está habilitado por defecto para clases
que especifican un mapeo <cache>.
ej.
true|false
hibernate.cache.query_cache_factory
El nombre de clase de una interface QueryCache
personalizada, por defecto al StandardQueryCache
prefabricado.
ej.
classname.of.QueryCache
hibernate.cache.region_prefix
Un prefijo a usar para los nombres de región
del caché de segundo nivel.
ej.
prefix
hibernate.cache.use_structured_entries
Fuerza a Hibernate a almacenar los datos en el caché
de segundo nivel en un formato más amigable al humano.
ej.
true|false
Propiedades de Transacción de Hibernate
Nombre de propiedad
Propósito
hibernate.transaction.factory_class
El nombre de clase de un TransactionFactory
a usar con la API de Transaction de Hibernate
(por defectoa JDBCTransactionFactory).
ej.
classname.of.TransactionFactory
jta.UserTransaction
Un nombre JNDI usado por JTATransactionFactory para
obtener la UserTransaction JTA del servidor
de aplicaciones.
ej.
jndi/composite/name
hibernate.transaction.manager_lookup_class
El nombre de clase de un TransactionManagerLookup
requerido cuando el chaché a nivel de JVM está
habilitado o cuando se usa un generador alto/bajo en un
entorno JTA.
ej.
classname.of.TransactionManagerLookup
hibernate.transaction.flush_before_completion
De habilitarse, la sesión se limpiará (flushed)
automáticamente durante la fase previa a la compleción
de la transacción. (Muy útil cuando se usa Hibernate
con CMT).
ej.
true | false
hibernate.transaction.auto_close_session
De habilitarse, la sesión será cerrada automáticamente
durante la fase posterior a la compleción de la transacción.
(Muy útil cuando se usa Hibernate con CMT).
ej.
true | false
Propiedades Misceláneas
Nombre de propiedad
Propósito
hibernate.query.factory_class
Elige la implementación de parser HQL.
ej.
org.hibernate.hql.ast.ASTQueryTranslatorFactory or
org.hibernate.hql.classic.ClassicQueryTranslatorFactory
hibernate.query.substitutions
Mapeos de símbolos en consultas Hibernate a
símbolos SQL. (los símbolos puedem ser
nombres de función o literales, por ejemplo).
ej.
hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC
hibernate.hbm2ddl.auto
Exporta automáticamente DDL de esquema cuando
al crear la SessionFactory.
Con create-drop, el esquema de
base de datos será desechado cuando la
SessionFactory se cierre explícitamente.
ej.
update | create | create-drop
hibernate.cglib.use_reflection_optimizer
Habilita el uso de CGLIB en vez de refleccón en tiempo de
ejecución (propiedad a nivel de sistema). La reflección
a veces puede ser útil ante la aparición de problemas.
Observa que Hibernate siempre requiere CGLIB incluso si desactivas
el optimizador. No puedes establecer esta propiedad en
hibernate.cfg.xml.
ej.
true | false
SQL Dialects
You should always set the hibernate.dialect property to the correct
org.hibernate.dialect.Dialect subclass for your database. If you
specify a dialect, Hibernate will use sensible defaults for some of the
other properties listed above, saving you the effort of specifying them manually.
Dialectos SQL de Hibernate(hibernate.dialect)
RDBMS
Dialecto
DB2 org.hibernate.dialect.DB2Dialect
DB2 AS/400 org.hibernate.dialect.DB2400Dialect
DB2 OS390 org.hibernate.dialect.DB2390Dialect
PostgreSQL org.hibernate.dialect.PostgreSQLDialect
MySQL org.hibernate.dialect.MySQLDialect
MySQL con InnoDB org.hibernate.dialect.MySQLInnoDBDialect
MySQL con MyISAM org.hibernate.dialect.MySQLMyISAMDialect
Oracle (cualquier versión) org.hibernate.dialect.OracleDialect
Oracle 9i/10g org.hibernate.dialect.Oracle9Dialect
Sybase org.hibernate.dialect.SybaseDialect
Sybase Anywhere org.hibernate.dialect.SybaseAnywhereDialect
Microsoft SQL Server org.hibernate.dialect.SQLServerDialect
SAP DB org.hibernate.dialect.SAPDBDialect
Informix org.hibernate.dialect.InformixDialect
HypersonicSQL org.hibernate.dialect.HSQLDialect
Ingres org.hibernate.dialect.IngresDialect
Progress org.hibernate.dialect.ProgressDialect
Mckoi SQL org.hibernate.dialect.MckoiDialect
Interbase org.hibernate.dialect.InterbaseDialect
Pointbase org.hibernate.dialect.PointbaseDialect
FrontBase org.hibernate.dialect.FrontbaseDialect
Firebird org.hibernate.dialect.FirebirdDialect
Recuperación por Unión Externa (Outer Join Fetching)
Si tu base de datos soporta uniones externas del estilo ANSI, Oracle o Sybase, la
recuperación por unión externa aumentará
frecuentemente el rendimiento limitando el número de llamadas a la base de datos
(al costo de más trabajo posiblemente realizado por la base de datos misma).
La recuperación por unión externa permite que un grafo completo de objetos
conectados por asociaciones muchos-a-uno, uno-a-muchos, muchos-a-muchos y uno-a-uno sea
traído en una sola SELECT SQL.
La recuperación por unión externa puede ser deshabilitada
globalmente estableciendo la propiedad
hibernate.max_fetch_depth a 0.
Un valor de 1 o mayor habilita la recuperación
por unión externa para asociaciones uno-a-uno y muchos-a-uno que
hayan sido mapeadas con fetch="join".
Ver para más información.
Flujos Binarios
Oracle limita el tamaño de arrays de byte
que puedan ser pasados a/desde su driver JDBC. Si deseas usar instancias
grandes de tipo binary o serializable,
debes habilitar hibernate.jdbc.use_streams_for_binary.
Esta es una propiedad a nivel de sistema solamente.
Caché de segundo nivel y de lectura
Las propiedades prefijadas por hibernate.cache
te permiten usar un sistema de caché de segundo nivel
en el ámbito de un proceso o cluster con Hibernate.
Ver para más detalles.
Sustitución de Lenguaje de Consulta
Puedes definir nuevos símbolos de consulta de Hibernate usando
hibernate.query.substitutions. Por ejemplo:
hibernate.query.substitutions true=1, false=0
causaría que los símbolos true y false sean
traducidos a literales enteros en el SQL generado.
hibernate.query.substitutions toLowercase=LOWER
te permitiría renombrar la función LOWER de SQL.
Hibernate statistics
Si habilitas hibernate.generate_statistics, Hibernate
expondrá un número de métricas que son útiles
al afinar un sistema en ejecución vía
SessionFactory.getStatistics(). Hibernate puede incluso ser
configurado para exponer estas estadísticas vía JMX. Lee el
Javadoc de las interfaces en org.hibernate.stats
para más información.
Registros de mensajes (Logging)
Hibernate registra varios eventos usando commons-logging
de Apache.
El servicio de commons-logging saldrá directamente ya sea a
Log4J (si incluyes log4j.jar in your classpath) o
JDK1.4 logging (al ejecutar bajo JDK1.4 o superior). Puedes descargar
Log4J desde http://logging.apache.org. Para usar
Log4J necesitarás colocar un fichero log4j.properties
en tu classpath. Un fichero de propiedades de ejemplo se distribuye con
Hibernate en el directorio src/.
Recomendamos fuertemente que te familiarices con los registros de mensajes
de Hibernate. Se ha puesto un gran trabajo en hacer los registros de Hibernate
tan detallados como se puede, sin hacerlos ilegibles. Es un dispositivo esencial
en la resolución de problemas. Las categorías de registro
más interesantes son las siguientes:
Categorías de Registro de Hibernate
Categoría
Función
org.hibernate.SQL
Registra todas las sentencias DML de SQL a
medida que se ejecutan
org.hibernate.type
Registra todos los parámetros JDBC
org.hibernate.tool.hbm2ddl
Registra todas las sentencias DDL de SQL a
medida que se ejecutan
org.hibernate.pretty
Registra el estado de todas las entidades (máximo
de 20 entidades) asociadas con la sesión en tiempo
de limpieza (flush)
org.hibernate.cache
Registra toda la actividad del caché de segundo nivel
org.hibernate.transaction
Registra la actividad relacionada con la transacción
org.hibernate.jdbc
Registra toda adquisición de recursos JDBC
org.hibernate.hql.ast
Regista los ASTs de HQL y SQL, así como
otra información sobre análisis de consultas.
org.hibernate.secure
Registra todas las peticiones de autorización JAAS
org.hibernate
Registra todo (mucha información, pero muy útil
para la resolución de problemas)
Al desarrollar aplicacinoes con Hibernate, casi siempre debes trabajar con
debug habilitado para la categoría org.hibernate.SQL
o, alternativamente, la propiedad hibernate.show_sql habilitada.
Implementando una NamingStrategy
La interface org.hibernate.cfg.NamingStrategy te permite
especificar un "estándar de nombrado" para objetos de la base de datos
y elementos de esquema.
Puedes proveer reglas para generar automáticamente identificadores de
base de datos a partir de identificadores JDBC o para procesar nombres
"lógicos" de columnas y tablas dados en el fichero de mapeo en nombres
"físicos" de columnas y tablas. Esta funcionalidad ayuda a reducir
la verborragia del documento de mapeo, eliminando ruido repetitivo
(prefijos TBL_, por ejemplo). La estrategia por defecto
usada por Hibernate mínima en absoluto.
Puedes especificar una estrategia diferente llamando a
Configuration.setNamingStrategy() antes de agregar los mapeos:
org.hibernate.cfg.ImprovedNamingStrategy
es una estrategia prefabricada que puede ser un punto de
partida útil para algunas aplicaciones.
Fichero de configuración XML
Un enfoque alternativo de configuración es especificar una
configuración completa en un fichero llamado hibernate.cfg.xml.
Este fichero puede ser usado como un remplazo del fichero hibernate.properties o,
si ambos están presentes, para sobrescribir propiedades.
El fichero de configuración XML se espera por defecto en la
raíz o tu CLASSPATH. He aquí un ejemplo:
java:/comp/env/jdbc/MyDB
org.hibernate.dialect.MySQLDialect
false
org.hibernate.transaction.JTATransactionFactory
java:comp/UserTransaction
]]>
Como puedes ver, la ventaja de este enfoque es la externalización de los
nombres de los fichero de mapeo a configuración. El
hibernate.cfg.xml es también más conveniente
una vez que hayas afinado el caché de Hibernate. Observa que elección
tuya usar ya sea hibernate.properties o
hibernate.cfg.xml, ambos son equivalentes, excepto por los
beneficios de usar la sintaxis XML arriba mencionados.
Con la configuración XML, arrancar Hibernate es tan simple como
Puedes tomar un fichero XML diferente usando
Integració con Servidores de Aplicaciones J2EE
Hibernate tiene los siguientes puntos de integración con la
infraestructura J2EE:
Datasources manejados por contenedor: Hibernate puede usar
conexiones JDBC manejadas por el contenedor y provistas a través de JNDI.
Usualmente, un TransactionManager compatible con JTA y un
ResourceManager cuidan del manejo de transacciones (CMT),
esp. manejo de transacciones distribuídas a través de varios
datasources. Puedes también, por supuesto, demarcar los límites
de las transacciones programáticamente (BMT) o podrías querer usar
para esto la API opcional de Transaction de Hibernate para
mantener tu código portable.
Ligamento Automático JNDI: Hibernate puede ligar sus
SessionFactory a JNDI después del arranque.
Ligamento de Sesión JTA:
La Session de Hibernate puede ser ligada automáticamente
al ámbito de transacciones JTA si usas EJBs. Simplemente busca la
SessionFactory de JNDI y obtén la Session
actual. Deja que Hibernate cuide de limpiar y cerrar la Session
cuando se complete tu transacción JTA. La demarcación de transacción
es declarativa, en descriptores de despliegue de EJB.
Despliegue JMX: Si tienes un servidor de aplicaciones capaz
de JMX (por ejemplo, JBoss AS), puedes optar por desplegar Hibernate como un MBean
manejado. Esto te ahorra el código de una línea de arranque para
construir tu SessionFactory desde una Configuration.
El contenedor arrancará tu HibernateService, e idealmente también
cuidará de las dependencias entre servicios (El datasource debe estar
disponible antes que arranque Hibernate, etc).
Dependiendo de tu entorno, podrías tener que establecer la opción
de configuración hibernate.connection.aggressive_release
a true si tu servidor de aplicaciones muestra excepciones "connection containment".
Configuración de la estrategia de transacción
La API de Session de Hibernate es independiente de cualquier
demarcación de transacción en tu arquitectura. Si dejas que Hibernate
use JDBC directamente, a través de un pool de conexiones. puedes comenzar y
acabar tus transacciones llamando la API de JDBC. Si ejecutas en un servidor de
aplicaciones J2EE, podréas querer usar transacciones manejadas por bean y
llamar la API de JTA y UserTransaction cuando sea necesario.
Para mantener tu código portable entre estos dos (y otros) entornos recomendamos la API
de Transaction de Hibernate, que envuelve y oculta el sistema subyacente.
Tienes que especificar una clase fábrica para las instancias de Transaction
estableciendo la propiedad de configuración hibernate.transaction.factory_class
de Hibernate.
Hay tres elecciones estándar (prefabricadas):
org.hibernate.transaction.JDBCTransactionFactory
delega a transacciones de base de datos (JDBC) (por defecto)
org.hibernate.transaction.JTATransactionFactory
delega a transacciones manejadas por contenedor si una transacción
existente estó por debajo en este contexto (ej. método de un
bean de sesión EJB), en otro caso una nueva transacción es
comenzada y se usan transacciones manejadas por bean.
org.hibernate.transaction.CMTTransactionFactory
delega a transacciones JTA manejadas por contenedor
Puedes definir también tus propias estrategias de transacción
(para un servicio de transacción CORBA, por ejemplo).
Algunas funcionalidades en Hibernate (ej, el caché de segundo nivel, ligamento
automático de JTA y Session, etc.) requieren acceso al TransactionManager
de JTA en un entorno manejado. En un servidor de aplicaciones tienes que especificar
cómo Hibernate debe obtener una referencia al TransactionManager,
pues J2EE no estandariza un solo mecanismo:
TransactionManagers de JTA
Transaction Factory
Servidor de Aplicaciones
org.hibernate.transaction.JBossTransactionManagerLookup
JBoss
org.hibernate.transaction.WeblogicTransactionManagerLookup
Weblogic
org.hibernate.transaction.WebSphereTransactionManagerLookup
WebSphere
org.hibernate.transaction.WebSphereExtendedJTATransactionLookup
WebSphere 6
org.hibernate.transaction.OrionTransactionManagerLookup
Orion
org.hibernate.transaction.ResinTransactionManagerLookup
Resin
org.hibernate.transaction.JOTMTransactionManagerLookup
JOTM
org.hibernate.transaction.JOnASTransactionManagerLookup
JOnAS
org.hibernate.transaction.JRun4TransactionManagerLookup
JRun4
org.hibernate.transaction.BESTransactionManagerLookup
Borland ES
SessionFactory ligada a JNDI
Una SessionFactory de Hibernate ligada a JNDI puede simplificar
la obtención de la fábrica y la creación de nuevas
Sessions. Observa que esto no está relacionado a un
Datasource ligado a JNDI, simplemente ambos usan el mismo
registro!
Si deseas tener la SessionFactory ligada a un espacio de nombres de JNDI,
especifica un nombre (ej. java:hibernate/SessionFactory) usando la
propiedad hibernate.session_factory_name. Si esta propiedad es omitida,
la SessionFactory no será ligada a JNDI (Esto es especialmente
útil en entornos con una implementació JNDI de sólo lectura por defecto,
ej. Tomcat.)
Al ligar la SessionFactory a JNDI, Hibernate usará los valores de
hibernate.jndi.url, hibernate.jndi.class para instanciar
un contexto inicial. Si étos no se especifican, se usará el
InitialContext por defecto.
Hibernate colocará automáticamente la SessionFactory
en JNDI después que llames a cfg.buildSessionFactory().
Esto significa que tendrás al menos esta llamada en algún código
de arranque (o clase de utilidad) en tu aplicación, a menos qie uses el despliegue
JMX con el HibernateService (discutido luego).
Si usas una SessionFactory de JNDI, un EJB o cualquier otra
clase puede obtener la SessionFactory usando una búsqueda
JNDI. Observa que esta configuración no es necesaria si usas la clase de ayuda
HibernateUtil introducida en el capítulo uno, que actúa
como un registro Singleton. Sin embargo, HibernateUtil es más
común en un entorno no manejado.
Ligado automático de JTA y Session
Para entornos no manejados hemos sugerido HibernateUtil con una
SessionFactory estática, y administración de la
Session de Hibernate. Este enfoque no es fácil de usar
en un entorno EJB, al poder ejecutarse muchos EJBs dentro de la misma transacción
pero no en la misma hebra. Recomendados que ligues la SessionFactory
a JNDI en un entorno manejado.
En vez de rodar tu propia utilidad de ThreadLocal,
usa el método getCurrentSession() en la
SessionFactory para obtener una Session
de Hibernate. Si no hubiese una Session de Hibernate en la
transacción JTA actual, se arrancará y asignará una.
Ambas opciones de configuración hibernate.transaction.flush_before_completion
y hibernate.transaction.auto_close_session, serán establecidas
automáticamente para cada Session que obtengas con
getCurrentSession(), de modo que éstas serán
limpiadas (flushed) y cerradas automáticamente cuando el contenedor complete
las transacciones JTA.
Si tu, por ejemplo, usas el patrón de diseño DAO para escribir tu
capa de persistencia, todos los DAO's buscan la SessionFactory
cuando se necesite y abren la sesión "actual". No hay necesidad de pasar
las instancias de SessionFactory o Session
alrededor entre el código de control y el código DAO.
Despliegue JMX
La línea cfg.buildSessionFactory() todavía tiene
que ser ejecutada en algun sitio para obtener una SessionFactory
en JNDI. Puedes hacer esto bien en un bloque inicializador static
(como aquel en HibernateUtil) o bien despliegas Hibernate como un
servicio manejado.
Hibernate se distribuye con org.hibernate.jmx.HibernateService
para despliegue en un servidor de aplicaciones con capacidades JMX, como JBoss AS.
El despliegue y la configuracón reales son específicos del vendedor.
He aquí un jboss-service.xml de ejemplo para JBoss 4.0.x:
jboss.jca:service=RARDeployer
jboss.jca:service=LocalTxCM,name=HsqlDS
java:/hibernate/SessionFactory
java:HsqlDS
org.hibernate.dialect.HSQLDialect
org.hibernate.transaction.JTATransactionFactory
org.hibernate.transaction.JBossTransactionManagerLookup
true
true
5
true
org.hibernate.cache.EhCacheProvider
true
true
auction/Item.hbm.xml,auction/Category.hbm.xml
]]>
Este fichero es desplegado en un directorio llamado META-INF y
empaquetado en un fichero JAR con la extensión .sar
(fichero de servicio). También necesitas empaquetar Hibernate, sus bibliotecas
de terceros requeridas, tus clases persistentes compiladas, así como tus ficheros de mapeo
en el mismo fichero. Tus beans de empresa (usualmente beans de sesión) pueden ser
mantenidos en su propio fichero JAR, pero debes incluir este fichero EJB JAR en el fichero
de servicio principal para obtener una unidad desplegable (en caliente). Consulta la documentación
de JBoss AS para más información sobre el servicio JMX y despliegue de EJB.