miércoles, 17 de marzo de 2010

Manejo de Transacciones con Hibernate y Spring AOP

En esta oportunidad hablaremos de la forma como configurar Spring AOP y Hibernate para el manejo de transacciones.

AOP (Programación Orientada a Aspectos) : es un paradigma de programación relativamente reciente cuya intención es permitir una adecuada modularización de las aplicaciones y posibilitar una mejor separación de conceptos. EL AOP siglas en inglés de la Programción Orientada a Aspectos, permite encapsular conceptos que componen una aplicación, en esta oportunidad la transaccionalidad de los métodos.

En cristiano todos los métodos que cumplan determinadas reglas definidas por nosotros, serán manejadas como transacción sin necesidad de haber indicado de forma programática dicha funcionalidad.

Para ello simplemente definiremos el applicationContext.xml de la siguiente manera.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
 
<-- Definiendo el DataSource --> 
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="/WEB-INF/jdbc.properties"/>
</bean>

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">       
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>



<-- Configurando Hibernate con Pool de Conecciones c3p0  -->

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource">
    <property name="mappingDirectoryLocations">
        <list>
            <value>classpath:/mapping
        </list>         
    </property>
        

    <property name="hibernateProperties">
        <props>
             <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
             <prop key="hibernate.hbm2ddl.auto">update</prop>
             <prop key="hibernate.show_sql">true</prop>
             true</prop>

             <prop key="hibernate.c3p0.min_size">5</prop> 
             <prop key="hibernate.c3p0.max_size">20</prop> 
             <prop key="hibernate.c3p0.timeout">300</prop> 
             <prop key="hibernate.c3p0.max_statements">50</prop> 
             <prop key="hibernate.c3p0.idle_test_period">3000</prop>
    
             <prop key="hibernate.jdbc.batch_size">20</prop>
             <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
             <prop key="hibernate.cache.use_structured_entries">true
        </props>
    </property>
</bean>


<-- Configurando el manejo de Transacciones con AOP  -->
     
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>
 
<tx:advice id="txAdvice" transaction-manager="txManager">     
    <tx:attributes>         
        <tx:method name="list*, get*, find*, exist*, load*" read-only="true"/>       
        <tx:method name="insert*, delete*, update*, save*" rollback-for="Throwable"/>    
        <tx:method name="*" rollback-for="Throwable"/>     
    </tx:attributes> 
</tx:advice>
    

<aop:config>
    <aop:pointcut id="serviceOperation" expression="execution(* pedro.rios.demo.service.*Service.*(..))"/>
    <aop:pointcut id="genericOperation" expression="execution(* pedro.rios.common.service.*Service.*(..))"/>
   
    <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="genericOperation"/>
</aop:config>


</beans>


Listo es todo lo que tenemos que hacer.. de lo demás se encarga el poderoso Spring. xD

Explicaremos:
Como podemos apreciar la cadena de conexión se sacará desde un archivo .properties para un mejor manejo en ambientes de producción.
solo hay que definir dicho archivo dentro de WEB-INF con el nombre de jdbc.properties; de esa forma se aprecia mejor y haces que tu framework sea más reutilizable.

Por otro, lado hemos definido pool de conecciones con C3P0.

El algoritmo que ya viene incluido en Hibernate para el "pooling" de conexiones es, sin embargo, bastante rudimentario. Fue concebido más que nada para ayudarlo a dar los primeros pasos, no para ser usado en un sistema de producción, ni siquiera para un test de performance.

Por eso deberías usar un "pool" de algún tercero para asegurar mayor redimiento y estabilidad. Simplemente reemplace la propiedad hibernate.connection.pool_size con propiedades específicas de la herramienta de "pooling" de su elección. Esto desactivará el "pooling" interno de Hibernate. En nuestro caso usaremos C3P0.


Para más info de Hibernate checar la siguiente url (está en español :D):  http://www.hibernar.org/documentacion_es/castellano.html
Luego, estamos definiendo la regla de los métodos que serán interceptados por Spring AOP para darles transaccionalidad. Dicha intercepción para esta demo se aplicará para los archivos que cumplan la siguiente forma: expression="execution(* pedro.rios.demo.service.*Service.*(..))" y expression= "execution(* pedro.rios.common.service.*Service.*(..))"

Listo con esto terminamos la definición del manejo de transacciones con Hibernate y Spring AOP.

Saludos Cordiales.. espero que les sirva esta demo....






3 comentarios:

David dijo...

gracias!! esto me sirve mucho, no sabía que hibernate era tan precario con el pool de conexiones. saludos desde argentina!!

Anónimo dijo...

Siento que sería un poco más entendible si pusieras las clases java de ejemplo.

Ramiro dijo...

Muchas gracias, muy bien explicado.

Publicar un comentario