viernes, 25 de enero de 2008

Schema Update en Hibernate

Una de las funcionalidades que extrañaría mas si dejara de usar Hibernate es la capacidad de impactar el esquema de la base de datos en forma incremental y automática. Afortunadamente, nos podemos centrar en crear las entidades de negocio como POJOS, con sus atributos y relaciones sin tener la necesidad de crear manualmente las tablas, todo ésto mediante la tarea Ant SchemaUpdate.

Por ejemplo cuando agregamos una nueva entidad al hibernate.cfg.xml o nuevos atributos/relaciones a una entidad existente, al ejecutar la tarea se realiza una comparación entre el esquema de la base de datos actual y el que se deduce a partir de los mappings de Hibernate con las modificaciones. Tomando en cuenta las diferencias, se ejecutan las sentencias SQL necesarias para sincronizar el modelo (básicamente CREATE TABLE ... y ALTER TABLE ...).

Debemos incluir en el build.xml el siguiente target:

<target name="schema.update" description="Update Schema" depends="build">
<taskdef name="schemaupdate" classname="org.hibernate.tool.hbm2ddl.SchemaUpdateTask"
classpathref="class.path">
<schemaupdate config="${conf.dir}/hibernate.cfg.xml"
quiet="no"
text="no">
</schemaupdate>
</taskdef>
</target>

Es importante aclarar que ésta herramienta no borra estructuras ya creadas, es decir no hace DROPS de tablas ni campos que hayan quedado sin usar, tampoco crea índices definidos por el programador (las restricciones de integridad referencial si las crea). La gente de Hibernate no lo considera un bug, según la documentación oficial, el SchemaUpdate está pensado para usarse en ambiente de desarrollo, se basa en la metadata que brinda el API JDBC, el cual no es consistente en todos los drivers. Como comentario, yo lo vengo usando desde hace tiempo sin problemas con MySQL, solo tengo en cuenta la restricción de los índices, los cuales creo manualmente.

Además de la tarea Ant, también es muy útil la opción para que el esquema se actualice automáticamente en el start up de la aplicación. En el hibernate.cfg.xml, mediante el property:
<property name="hbm2ddl.auto">update</property>

indicamos que la primera vez que se use la SessionFactory, ejecute las modificaciones a la base de datos, al igual que lo haría la tarea Ant. Ésta opción la uso mucho para las instalaciones en producción, en desarrollo uso Ant para no enlentecer los deploys.

Hasta el próximo post!

domingo, 20 de enero de 2008

Mucho más que solo programadores

El rol del programador se ha vuelto fundamental en el resultado final de las soluciones de software, muchas veces marca el rumbo seleccionando metodologías y tecnologías de desarrollo, sus responsabilidades no se limitan a "picar código", por eso su cotización está en alza.

Generalizando, podríamos identificar dos perfiles de programadores muy distintos:

Los que en cada proyecto intentan cambiar el esquema de desarrollo por las últimas novedades o frameworks mas allá de la relación costo/beneficio, además consideran la innovación como un fin en si mismo, no como herramienta para lograr la solución que el cliente necesita. Pueden quedar atrapados en la carrera de ratas.

Por otro lado están los que siguen haciendo las cosas como hace diez años y no les preocupa para nada las tendencias del mercado, consideran de que si el cliente no solicita la evolución es porque no lo necesita, hay una actitud pasiva que provoca un estancamiento tecnológico.

No se si es un tema de edad, pero me da la impresión de que cuando nos iniciamos laboralmente estamos mas cerca de la primera posición, queremos usar cuanta tecnología y "chiche" nuevo sale al mercado y nos desmotivamos si alguien no está de acuerdo.

Luego con los años empezamos a ser mas selectivos, tratamos de enfocarnos en implementar la lógica de negocio porque la mayoría de los desafíos técnicos ya están resueltos, se incorporan nuevas tecnologías solo si agregan valor, no por modas pasajeras. Aquí está el punto de inflexión, podemos permanecer en ésta posición de equilibrio o mutar al otro extremo, donde nos quedamos estancados tecnológicamente.

Un caso muy común es el de los programadores Cobol, luego de permanecer durante muchos años en la misma plataforma, se encuentran en la situación de que las empresas en dónde trabajan comienzan a migrar sus sistemas hacia otras arquitecturas menos costosas. Reciclar a esos profesionales es muy difícil, pasar del esquema procedural monolítico al mundo dinámico de la orientación a objetos y de las tecnologías web requiere un cambio de cabeza importante.

Por eso mas allá de los conocimientos técnicos sobre una determinada tecnología, creo que lo mas importante es que podamos adaptarnos a las distintas situaciones sobre la marcha y además evitar quedar presos en el fanatismo tecnológico.

Hasta el próximo post!

martes, 15 de enero de 2008

Isolation Level en Hibernate

El isolation level o nivel de aislamiento es una de las configuraciones a nivel de base de datos que en ocasiones olvidamos establecer.
Podríamos decir que determina la forma en que los datos son "lockeados" o aislados de otros procesos mientras son accedidos, es decir, define como y cuando los cambios realizados por una transacción son visibles por otras operaciones concurrentes, influyendo en las siguientes anomalías:

Dirty Reads: Ocurre cuando una transacción lee datos modificados por otros procesos concurrentes que aún no han realizado commit, por eso se la denomina lectura sucia.

Nonrepeatable Reads: Ocurre cuando dentro de una transacción se lee el mismo registro mas de una vez y los datos obtenidos son diferentes, seguramente porque otro proceso concurrente los actualizó.

Phantom Reads: Ocurre cuando en una transacción ejecutamos el mismo query mas de una vez y obtenemos distintos resultados, por ejemplo si otra transacción agregó nuevos registros que satisfacen el criterio de búsqueda de la consulta.

El estándar ANSI/ISO SQL define cuatro niveles de aislamiento:

READ UNCOMMITTED: Permite que se produzcan Dirty Reads, Nonrepeatable Reads y PhantomReads. Es la opción menos restrictiva, recomendable si se manejan datos de solo lectura o muy pocas actualizaciones.

READ COMMITTED: Evita Dirty Reads, pero permite que se produzcan Nonrepeatable Reads y Phantom Reads.

REPEATABLE READ: Solo permite que se produzcan Phantom Reads.

SERIALIZABLE: Evita todos los casos anteriores, es la opción mas restrictiva.

Cada manejador de base de datos tiene su forma de configurar el isolation level a través de un administrador gráfico o por línea de comandos, por otro lado también es bueno aclarar que los productos difieren en los valores por defecto, por ejemplo en MySQL el default es REPEATABLE READ, en cambio en Oracle y SQL Server es READ COMMITTED.

Si usamos Hibernate como framework de persistencia podemos usar el property "hibernate.connection.isolation" en el hibernate.cfg.xml. Por ejemplo, para establecer la estrategia READ COMMITTED usaríamos:

<property name="hibernate.connection.isolation">2</property>

Los valores posibles son los mismos que define la interface java.sql.Connection:

1: READ UNCOMMITTED
2: READ COMMITTED
4: REPEATABLE READ
8: SERIALIZABLE

Tener en cuenta la aclaración de la documentación oficial : "... note that most databases do not support all isolation levels". Ante la duda siempre lo mejor es hacer una prueba ejecutando dos transacciones en paralelo para verificar que tenemos el comportamiento esperado.

Hasta el próximo post!