Foros del Web » Programación para mayores de 30 ;) » Java »

Problema con Spring Transactions e Hibernate

Estas en el tema de Problema con Spring Transactions e Hibernate en el foro de Java en Foros del Web. Hola a todos: Soy nuevo en este foro. Mi nombre es Adolfo. Tengo un problema con las transacciones de Spring, y lo envío a este ...
  #1 (permalink)  
Antiguo 25/05/2012, 06:18
 
Fecha de Ingreso: mayo-2012
Mensajes: 3
Antigüedad: 12 años
Puntos: 0
Mensaje Problema con Spring Transactions e Hibernate

Hola a todos:

Soy nuevo en este foro. Mi nombre es Adolfo.

Tengo un problema con las transacciones de Spring, y lo envío a este foro, para ver si alguien me puede ayudar a solucionarlo.

Estoy atascado en un punto donde no sé salir, pues no me da error, pero no hace lo que se supone que debería hacer.

Tengo un DAO (PersonaDAO) que hereda de HibernateDaoSupport con estos métodos:

Código:
  public void save(final Persona p) {
   this.getHibernateTemplate().saveOrUpdate(p);
  }

  public void savePersonas(final List<Persona> personas) {
    for (final Persona persona : personas) {
     this.save(persona);
    }
  }
Y luego en el programa principal, llamo a savePersonas, con un List de objetos de tipo Persona, con uno de ellos mal que salta una excepción al salvarlo.

Código:
  final ApplicationContext appCtx = new ClassPathXmlApplicationContext(configFile);

  final IPersonaDAO dao = (IPersonaDAO) appCtx.getBean("miDao");

  final List<Persona> personas = new ArrayList<Persona>();

  final Persona p1 = new Persona();
  p1.setEdad(9);
  p1.setNombre("adolfo");
  personas.add(p1);

  final Persona p2 = new Persona();
  p2.setEdad(9);
  p2.setNombre(null); // va a dar error al insertar y debería hacer rollback
  personas.add(p2);

  dao.savePersonas(personas);
Entiendo que si añado transaccionalidad al método save mediante AOP, debería hacer un rollback y no guardar ninguno de los objetos que le paso en el List.

Pero no lo hace, me guarda el primero (que no da error) y luego salta la excepción y termina el programa.

He probado con este fichero de configuración:

Código:
<?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">

  <bean id="miDao"
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager">
      <ref local="transactionManager" />
    </property>
    <property name="target">
      <ref local="daoTarget" />
    </property>
    <property name="transactionAttributes">
      <props>
        <prop key="save*">PROPAGATION_REQUIRED</prop>
      </props>
    </property>
  </bean>

  <bean id="daoTarget" class="dao.PersonaDAO">
    <property name="sessionFactory">
      <ref local="sessionFactory" />
    </property>
  </bean>

  <bean id="transactionManager"
    class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory">
      <ref bean="sessionFactory" />
    </property>
  </bean>
  
  <bean id="sessionFactory"
    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource">
      <ref local="myDataSource" />
    </property>
    <property name="mappingResources">
      <list>
        <value>model/persona.hbm.xml</value>
      </list>
    </property>
    <property name="hibernateProperties">
      <props>
        <prop key="hibernate.dialect">
          org.hibernate.dialect.MySQLDialect
        </prop>
        <prop key="hibernate.connection.pool_size">1</prop>
        <prop key="hibernate.show_sql">false</prop>
        <prop key="hibernate.hbm2ddl.auto">create</prop>
      </props>
    </property>
  </bean>
  
  <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName">
      <value>com.mysql.jdbc.Driver</value>
    </property>
    <property name="url">
      <value>jdbc:mysql://localhost/clase</value>
    </property>
    <property name="username">
      <value>clase</value>
    </property>
    <property name="password">
      <value>clase</value>
    </property>
  </bean>
  
</beans>
Y también he probado con este otro fichero de configuración:

Código:
<?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">


  <bean id="miDao" class="dao.PersonaDAO">
    <property name="sessionFactory">
      <ref local="miSessionFactory" />
    </property>
  </bean>

  <bean id="miSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource">
      <ref local="miDataSource" />
    </property>
    <property name="mappingResources">
      <list>
        <value>model/persona.hbm.xml</value>
      </list>
    </property>
    <property name="hibernateProperties">
      <props>
        <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
        <prop key="hibernate.show_sql">false</prop>
        <prop key="hibernate.hbm2ddl.auto">create</prop>
      </props>
    </property>
  </bean>

  <bean id="miDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName">
      <value>com.mysql.jdbc.Driver</value>
    </property>
    <property name="url">
      <value>jdbc:mysql://localhost:3306/clase</value>
    </property>
    <property name="username">
      <value>clase</value>
    </property>
    <property name="password">
      <value>clase</value>
    </property>
  </bean>
  
  <aop:config>
    <aop:pointcut id="daoPoincut" expression="execution(* dao.*.*(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="daoPoincut" />
  </aop:config>
  
  <tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
      <tx:method name="list*" read-only="true" />
      <tx:method name="save*" />
    </tx:attributes>
  </tx:advice>

  <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="miDataSource" />
  </bean>

</beans>
Las librerías que uso son las siguientes:

Código:
  antlr-2.7.7.jar
  aopalliance-1.0.jar
  aspectjrt-1.6.12.jar
  aspectjweaver-1.6.12.jar
  cglib-nodep-2.2.2.jar
  commons-collections-3.2.1.jar
  commons-dbcp-1.4.jar
  commons-logging-1.1.1.jar
  commons-pool-1.6.jar
  dom4j-1.6.1.jar
  hibernate-3.2.7.ga.jar
  jta-1.1.jar
  mysql-connector-java-5.1.19.jar
  spring-aop-2.5.6.SEC03.jar
  spring-beans-2.5.6.SEC03.jar
  spring-context-2.5.6.SEC03.jar
  spring-core-2.5.6.SEC03.jar
  spring-dao-2.0.8.jar
  spring-jdbc-2.5.6.SEC03.jar
  spring-orm-2.5.6.SEC03.jar
  spring-tx-2.5.6.SEC03.jar

A ver si alguien me puedes echar una mano (aunque sea al cuello).

Un saludo.
Adolfo

-
No hay camino hacía el Software Libre. El Software Libre es el camino.
Sígueme en Twitter ([URL="http://twitter.com/asanzdiego"]@asanzdiego[/URL])
  #2 (permalink)  
Antiguo 25/05/2012, 09:48
Avatar de Fuzzylog  
Fecha de Ingreso: agosto-2008
Ubicación: En internet
Mensajes: 2.511
Antigüedad: 15 años, 8 meses
Puntos: 188
Respuesta: Problema con Spring Transactions e Hibernate

1º La transaccionalidad la implementas en el manager que llama a los daos
2º Mejor usando anotaciones
3º Para el rollback, por defecto sólo responde a RuntimeExcepcion, así que para que incluya otras tendrás que añadir la anotación @Transactional(rollbackFor = Exception.class)
// Dentro de @Transactional puedes añadir el tipo de propagación, etc...
4º En tu caso veo que llamas al método save y el primero te lo guarda bien. Hasta donde sé, por el tipo de acceso que tienes, permite leer la tabla antes de realizar el primer insert, y al insertar tienes que hacer una lectura previa del maxId de la tabla para saber cual es el siguiente id primario que debe insertar. Yo le crearia un metodo getNextId() para obtener el idMax+1, y tendria ese elemento en una variable que setearia al objeto que deseo insertar. Pasado el insert del bucle for aumentaría ese nextId en 1 unidad .

Algo tal que así:

public void savePersonas(final List<Persona> personas) {
Integer nextId = null;
for (final Persona persona : personas) {
if (nextId == null) {
nextId = getNextId();
}
persona.setIdPersona(nextId);
this.save(persona);
nextId++;
}
}

Espero que haya aclarado tus dudas
__________________
if (fuzzy && smooth) {
fuzzylog = "c00l";
return true;
}
  #3 (permalink)  
Antiguo 25/05/2012, 16:19
 
Fecha de Ingreso: mayo-2012
Mensajes: 3
Antigüedad: 12 años
Puntos: 0
Mensaje Respuesta: Problema con Spring Transactions e Hibernate

Hola:

En primer lugar, muchas gracias por contestar.

En segundo lugar, usando:

Código:
@Transactional(rollbackFor = Throwable.class)
en el método del servicio que llama al dao, e indicando:

Código:
<tx:annotation-driven transaction-manager="txManager" />
en el spring.xml, me sigue sin hacer rollback al saltar una excepción.

He probado a poner:

Código:
@Transactional(propagation = ppropagation.MANDATORY, 
               rollbackFor = Throwable.class)
y me salta la exceción:

Código:
No existing transaction found for transaction
marked with propagation 'mandatory'
, así que parece que la anotación la recoge correctamente.

¿Vendrá el error por usar HibernateDaoSupport?

Un saludo.
Adolfo

-
No hay camino hacía el Software Libre. El Software Libre es el camino.
Sígueme en Twitter ( [URL="http://twitter.com/asanzdiego"]@asanzdiego[/URL] )
  #4 (permalink)  
Antiguo 26/05/2012, 04:20
Avatar de Fuzzylog  
Fecha de Ingreso: agosto-2008
Ubicación: En internet
Mensajes: 2.511
Antigüedad: 15 años, 8 meses
Puntos: 188
Respuesta: Problema con Spring Transactions e Hibernate

Prueba a usar estas anotaciones

isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, rollbackFor=Exception.class

Usa Exception, ya que las runtime ya las está recogiendo
haz siempre try catch y haz q las excepciones del dao llegen al manager
y se proyecten hacia el service, controlador o lo que uses. captura tanto las runtime como las Exception en el dao.

Sobre el hibernateDaoSupport no puedo decirte nada
__________________
if (fuzzy && smooth) {
fuzzylog = "c00l";
return true;
}
  #5 (permalink)  
Antiguo 27/05/2012, 15:19
 
Fecha de Ingreso: mayo-2012
Mensajes: 3
Antigüedad: 12 años
Puntos: 0
Respuesta: Problema con Spring Transactions e Hibernate

Es un problema de entorno. En ubuntu-10.04 no funciona y en windows-xp parece que sí. En otro momento pondré las versiones del jdk y de mysql que estaba utilizando en ubuntu-10.04 y que hacen que el ejemplo deje de funcionar.

Gracias por todo Fuzzylog.

Un saludo.
Adolfo
-
No hay camino hacía el Software Libre. El Software Libre es el camino.
Sígueme en Twitter (@asanzdiego)

Etiquetas: aop, hibernate, spring, transacciones
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 12:22.