230 lines
14 KiB
XML
230 lines
14 KiB
XML
|
<chapter id="best-practices" revision="3">
|
||
|
<title>Mejores Prácticas</title>
|
||
|
|
||
|
<variablelist spacing="compact">
|
||
|
<varlistentry>
|
||
|
<term>Escribe clase finamente granularizadas y mapealas usando <literal><component></literal>.</term>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Usa una clase <literal>Dirección</literal> para encapsular <literal>calle</literal>,
|
||
|
<literal>distrito</literal>, <literal>estado</literal>, <literal>código postal</literal>.
|
||
|
Esto alienta la reutilización de código y simplifica el refactoring.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term>Declara las propiedades identificadoras en clases persistentes.</term>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Hibernate hace opcionales las propiedades identificadoras. Existen todo tipo de razones
|
||
|
por las que debes usarlas. Recomendamos que los identificadores sean 'sintéticos'
|
||
|
(generados, sin ningún significado de negocio).
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term>Identifica las claves naturales.</term>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Identifica las claves naturales de todas las entidades, y mapealas usando
|
||
|
<literal><natural-id></literal>. Implementa <literal>equals()</literal> y
|
||
|
<literal>hashCode()</literal> para comparar las propiedades que componen la clave natural.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term>Coloca cada mapeo de clase en su propio fichero.</term>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
No uses un solo documento monolítico de mapeo. Mapea <literal>com.eg.Foo</literal> en
|
||
|
el fichero <literal>com/eg/Foo.hbm.xml</literal>. Esto tiene sentido particularmente en un
|
||
|
ambiente de equipo.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term>Carga los mapeos como recursos.</term>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Despliega los mapeos junto a las clases que mapean.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term>Considera externalizar las cadenas de consulta.</term>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Esta es una buena práctica si tus consultas llaman a funciones SQL que no son del
|
||
|
estándar ANSI. Externalizar las cadenas de consulta a ficheros de mapeo hará la
|
||
|
aplicación más portable.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term>Usa variables de ligado.</term>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Igual que en JDBC, siempre remplaza valores no constantes con "?". ¡Nunca uses manipulación
|
||
|
de cadenas para ligar un valor no constante en una consulta! Incluso mejor, considera usar
|
||
|
parámetros con nombre en las consultas.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term>No manejes tus propias conexiones JDBC.</term>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Hibernate deja a la aplicación administre las conexiones JDBC. Este enfoque debe considerarse
|
||
|
como último recurso. Si no puedes usar los provedores de conexión prefabricados, considera
|
||
|
prover tu propia implementación de <literal>org.hibernate.connection.ConnectionProvider</literal>.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term>Considera usar un tipo personalizado.</term>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Supón que tienes un tipo Java, digamos de alguna biblioteca, que necesita hacerse persistente
|
||
|
pero no provee los métodos de acceso necesarios para mapearlo como un componente. Debes considerar
|
||
|
implementar <literal>org.hibernate.UserType</literal>. Este enfoque libera al código de aplicación
|
||
|
de implementar transformaciones a / desde un tipo Hibernate.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term>Usa JDBC codificado a mano en cuellos de botella.</term>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
En áreas del sistema de rendimiento crítico, algunos tipos de operaciones podrían beneficiarse
|
||
|
del JDBC directo. Pero por favor, espero hasta que <emphasis>sepas</emphasis> que algo es
|
||
|
un cuello de botella. Y no asumas que el JDBC directo es necesariamente más rápido. Si necesitas
|
||
|
usar JDBC directo, podría ser valioso abrir una <literal>Session</literal> de Hibernate y usar esa
|
||
|
conexión JDBC. De esta forma puedes usar aún la misma estrategia de transacción y el mismo
|
||
|
proveedor de conexiones subyacente.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term>Comprende la limpieza (flushing) de <literal>Session</literal>.</term>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
De vez en cuando la sesión sincroniza su estado persistente con la base de datos. El rendimiento
|
||
|
se verá afectado si este proceso ocurre demasiado frecuentemente. A veces puedes minimizar
|
||
|
limpieza innecesaria deshabilitando la limpieza automática o incluso cambiando el orden de las
|
||
|
consultas u otras operaciones en una transacción en particular.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term>En una aplicación en tres gradas, considera usar objetos separados.</term>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Al usar una arquitectura de servlet / sesión, puedes pasar objetos persistentes en el bean de
|
||
|
sesión hacia y desde la capa de servlet / JSP. Usa una sesión nueva para atender el servicio de cada
|
||
|
petición. Usa <literal>Session.merge()</literal> o <literal>Session.saveOrUpdate()</literal> para
|
||
|
sincronizar los objetos con la base de datos.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term>En una arquitectura en dos gradas, considera usar contexto de persistencia largos.</term>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Las transacciones de base de datos tienen que ser tan cortas como sea posible. Sin embargo,
|
||
|
frecuentemente es necesario implementar <emphasis>transacciones de aplicación</emphasis>
|
||
|
ejecutándose en largo, una sola unidad de trabajo desde el punto de vista de un usuario.
|
||
|
Una transacción de aplicación puede abarcar muchos ciclos petición/respuesta del cliente.
|
||
|
Es común usar objetos separados para implementar transacciones de aplicación. Una alternativa,
|
||
|
extremadamente apropiada en arquitecturas en dos gradas, es mantener un solo contacto de persistencia
|
||
|
abierto (sesión) para todo el ciclo de vida de la transacción de aplicación y simplemente
|
||
|
desconectar de la conexión JDBC al final de cada petición, y reconectar al comienzo de la
|
||
|
petición subsecuente. Nunca compartas una única sesión a través de más de una transacción
|
||
|
de aplicación, o estarás trabajando con datos añejos.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term>No trates la excepciones como recuperables.</term>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Esto es más una práctica necesaria que una "mejor" práctica. Cuando ocurra una excepción,
|
||
|
deshaz (rollback) la <literal>Transaction</literal> y cierra la <literal>Session</literal>.
|
||
|
Si no lo haces, Hibernate no puede garantizar que el estado en memoria representa con exactitud
|
||
|
el estado persistente. Como un caso especial de esto, no uses <literal>Session.load()</literal>
|
||
|
para determinar si una instancia con el identificador dado existe en la base de datos. En cambio,
|
||
|
usa <literal>Session.get()</literal> o una consulta.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term>Prefiere la recuperación perezosa para las asociaciones.</term>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Usa escasamente la recuperación temprana. Usa proxies y colecciones perezosas para la mayoría
|
||
|
de asociaciones a clases probablemente no estén mantenidas en el caché de segundo nivel. Para
|
||
|
las asociaciones a clases en caché, donde hay una probabilidad de acceso a caché extremadamente
|
||
|
alta, deshabilita explícitamente la recuperación temprana usando <literal>lazy="false"</literal>.
|
||
|
Cuando sea apropiada la recuperación por unión (join fetching) para un caso de uso en particular,
|
||
|
usa una consulta con un <literal>left join fetch</literal>.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term>
|
||
|
Usa el patrón <emphasis>sesión abierta en vista</emphasis>, o una <emphasis>fase de ensamblado</emphasis>
|
||
|
disciplinada para evitar problemas con datos no recuperados.
|
||
|
</term>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Hibernate liberal al desarrollador de escribir <emphasis>Objetos de Transferencia de Datos
|
||
|
(Data Transfer Objects)</emphasis> (DTO). En una arquitectura tradicional de EJB, los DTOs tienen
|
||
|
un propósito doble: primero, atacan el problema que los beans de entidad no son serializables.
|
||
|
Segundo, definen implícitamente una fase de ensamblado cuando se recuperan y se forman (marshalling)
|
||
|
todos los datos a usar por la vista en los DTOs antes de devolver el control a la grada de
|
||
|
presentación. Hibernate elimina el primer propósito. Sin embargo, aún necesitas una fase
|
||
|
de ensamblado (piensa en tus métodos de negocio como si tuviesen un contrato estricto con la grada
|
||
|
de presentación sobre qué datos están disponibles en los objetos separados) a menos que estés
|
||
|
preparado para tener el contexto de persistencia (la sesión) abierto a través del proceso
|
||
|
de renderización de la vista. ¡Esta no es una limitación de Hibernate! Es un requerimiento
|
||
|
fundamental de acceso seguro a datos transaccionales.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term>Considera abstraer tu lógica de negocio de Hibernate</term>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Oculta el código de acceso a datos (Hibernate) detrás de una interface. Combina los patrones
|
||
|
<emphasis>DAO</emphasis> y <emphasis>Sesión de Hebra Local</emphasis>. Incluso puedes tener
|
||
|
algunas clases hechas persistentes por JDBC escrito a mano, asociadas a Hibernate por medio
|
||
|
de un <literal>UserType</literal>. (Este consejo está pensado para aplicaciones "suficientemente
|
||
|
grandes"; ¡no es apropiado para una aplicación con cinco tablas!)
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term>No uses mapeos de asociación exóticos.</term>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Son raros los casos de uso de asociaciones reales muchos-a-muchos. La mayor parte del tiempo
|
||
|
necesitas información adicional almacenada en una "tabla de enlace". En este caso, es mucho
|
||
|
mejor usar dos asociaciones uno-a-muchos a una clase de enlace intermedia. De hecho, pensamos
|
||
|
que la mayoría de asociaciones son uno-a-muchos y muchos-a-uno, debes ser cuidadoso al usr
|
||
|
cualquier otro estilo de asociación y preguntarte si es realmente necesario.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term>Prefiere las asociaciones bidireccionales.</term>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Las asociaciones unidireccionales son más difíciles de consultar. En una aplicación grande,
|
||
|
casi todas las asociaciones deben ser navegables en ambas direcciones en consultas.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
</variablelist>
|
||
|
|
||
|
</chapter>
|
||
|
|