2010-10-07 23 views
5

Estoy escribiendo una aplicación simple (Spring + Hibernate + PostgreSql db). Solo intento construir un objeto de muestra y persistir en db.Transacción de muelles - reversión automática de actualizaciones de db anteriores cuando una actualización db falla

corro un método main de la clase Java simple donde he cargado el applicationContext y tengo referencia a la clase de servicio de la siguiente manera Contexto

TestService srv = (TestService)factory.getBean("testService"); 

Aplicación - contexto:

<bean id="transactionManager" 
    class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="sessionFactoryVsm" /> 
</bean> 

<bean id="testService" class="com.test.service.TestServiceImpl"> 
    <property name="testDao" ref="testDao"/> 
</bean> 

<bean id="testDao" class="com.test.dao.TestDaoImpl> 
    <property name="sessionFactory" ref="sessionFactoryVsm"/> 
</bean> 

En TestService, he inyectado TestDao. En el método de servicio de prueba, he construido objetos para empleados emp1 y emp2 y llamo a dao dos veces para actualizar.

código TestDaoImpl:

public void saveOrUpdate(BaseDomainModel baseObject) { 

    Session session = null; 
    try { 
     session = getHibernateTemplate().getSessionFactory().openSession(); 
     session.saveOrUpdate(baseObject); 
     session.flush(); 
    } catch (Exception e) { 
     logger.error("Generic DAO:saveOrUpdate::" + e); 
     e.printStackTrace(); 
    } finally { 
     if (session != null) { 
      session.close(); 
     } 
    } 

} 

Cuando falla la actualización EMP2 EMP1 también debe fallar. Cómo puedo hacer eso. Por favor, asesoramiento

Gracias de antemano

Actualizado:

Gracias Nanda. Intenté una transacción declarativa. Pero no está funcionando. Emp1 persiste y no retrocede eveb. La segunda llamada dao falla. He agregado asesoramiento de transacción al método.

para probar si se aplica o no el consejo de la operación i cambiado la propagación de "NOT_SUPPORTED". pero aún emp1 persiste. la expectativa es que deberíamos tener el tipo de excepción de Transaction Not Supported. por favor aconséjame .

ACTUALIZADO

@seanizer - Gracias por la actualización. Incluso intenté agregar
@Transactional (propagation = Propagation.NOT_SUPPORTED) public void saveEmp (Employee emp) a ese método de servicio. Pero no funcionó. Además, repetir la retención de la colección solo es bueno si necesito llamar a un dao. Si en caso de tener que llamar a dos dao diferentes para persistir obj1 y obj2, esto puede no ser de ayuda. Solo para verificar si la transacción se está aplicando obtengo @Transactional (propagation = Propagation.NOT_SUPPORTED). Pero todavía obj1 persistió. Sólo dudo si la configuración xml/anotación dada es correcta. compruebe

<bean id="txManager" 
     class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
     <property name="sessionFactory" ref="sessionFactoryVsm" /> 
    </bean> 

<tx:advice id="txAdvice" transaction-manager="txManager"> 
    <tx:attributes> 
     <tx:method name="saveEmp" propagation="REQUIRED" rollback-for="Exception"/> 
     <tx:method name="*"/> 
    </tx:attributes> 
</tx:advice> 
<aop:config> 
    <aop:pointcut id="testServiceOperation" expression="execution(*com.test.service.*(..))"/> 
    <aop:advisor advice-ref="txAdvice" pointcut-ref="testServiceOperation"/> 
    </aop:config> 

estoy usando org.springframework.orm.hibernate3.HibernateTransactionManager para la transactionManager. Es esto correcto ?


Actualizado

He creado mi clase de excepción que se extiende desde myRuntimeExp RuntimeException y lanzando el mismo método de Dao con el método de servicio. pero aún así la reversión no está sucediendo.Dudo que haya dado correctamente las configuraciones en el applnContext.xml. ¿Alguien puede ayudarme a verificar si el asesoramiento/anotación de la transacción se está aplicando al método o no? ¿hay alguna manera de funcionar en un modo de depuración y comprobar

Edición:

que estaba usando

session = getHibernateTemplate().getSessionFactory().openSession(); 

Sin embargo, cabe sesión actual y se está trabajando muy bien.

session = getHibernateTemplate().getSessionFactory().getCurrentSession(); 

Respuesta

4

Si utiliza la gestión de transacciones declarativa, se puede perder la mayor parte de este texto modelo:

TestDaoImpl:

private SessionFactory sessionFactory; 

public void setSessionFactory(SessionFactory f){ 
    this.sessionFactory = f; 
} 

public void saveOrUpdate(BaseDomainModel baseObject) { 
    Session session = sessionFactory.getCurrentSession(); 
    session.saveOrUpdate(baseObject); 
} 

Y se puede controlar el manejo de la capa de servicio utilizando @Transactional transacción (o xml configuración)

TestServiceImpl:

private TestDao testDao; 

public void setTestDao(TestDao d){ 
    this.testDao = d; 
} 

@Transactional // one transaction for multiple operations 
public void someServiceMethod(Collection<BaseDomainModel> data){ 
    for(BaseDomainModel baseObject : data) 
     testDao.saveOrUpdate(baseObject); 
} 

Referencia:

1

Puede poner sessionFactory en TestServiceImpl y abrir la sesión allí.

+0

¿Sirve Spring Declarative Transaction en este caso? – Vaandu

+0

sí, por supuesto, declare que la transacción es necesaria en el momento Y en el nivel de servicio. Si el dao detecta que el servicio ha abierto la transacción, usará esto en lugar de crear una nueva transacción. – nanda

+0

No estoy de acuerdo, las transacciones deberían ser necesarias en los métodos de servicio, no en los métodos de dao. De esta forma, una llamada de servicio puede ser atómica incluso si usa múltiples métodos de dao (sí, sé que también puede lograrlo uniendo las transacciones existentes, pero prefiero una separación limpia de capas) –

4

Por defecto, Spring solamente deshace para excepción sin marcar. Debe proporcionar el rollback -attribute y especificar qué excepción está intentando atrapar.


A partir de la primavera documentation:

Sin embargo, debe tenerse presente que la transacción código de la infraestructura de la Spring Framework, por defecto, única marcar una transacción para reversión en el caso del tiempo de ejecución, excepciones sin marcar; es decir, cuando la excepción arrojada es una instancia o subclase de RuntimeException. ( errores también - por defecto -. Resultar en una reversión) verificaron excepciones lanzadas desde un método transaccional se no resultado en la transacción de ser cancelada.

+0

tenga en cuenta que también debe agregar esto: virgium03

+0

@ virgium03 - Gracias. Puedes ver el snipper xml anterior donde he dado . Esto debería tener cuidado, ¿estoy en lo correcto? – Vaandu

+0

también, puede cambiar el nivel de registro para depurar y ver cuándo se comprometen las transacciones, se retrotrae, etc. – virgium03

2

Aquí, obtener estos fragmentos y la esperanza de que le ayudará a:

<bean id="abstractService" 
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" 
abstract="true"> 
<property name="transactionManager" ref="transactionManager" /> 
<property name="transactionAttributes"> 
    <props> 
     <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> 
     <prop key="add*">PROPAGATION_REQUIRED, -Exception</prop> 
     <prop key="update*">PROPAGATION_REQUIRED, -Exception</prop> 
     <prop key="modify*">PROPAGATION_REQUIRED, -Exception</prop> 
     <prop key="delete*">PROPAGATION_REQUIRED, -Exception</prop> 
     <prop key="save*">PROPAGATION_REQUIRED, -Exception</prop> 
    </props> 
</property> 
</bean> 

<bean id="persistenceServiceTarget" class="com.blahblah.server.service.impl.PersistenceServiceImpl"> 
<property name="persistenceDAO" ref="persistenceDAO" /> 
</bean> 
<bean id="persistenceService" parent="abstractService"> 
    <property name="target" ref="persistenceServiceTarget" /> 
</bean> 

<tx:annotation-driven transaction-manager="transactionManager" /> 

<bean id="abstractDAO" 
class="org.springframework.orm.hibernate3.support.HibernateDaoSupport" 
abstract="true"> 
<property name="sessionFactory"> 
    <ref bean="webSessionFactory" /> 
</property> 
</bean> 

<bean id="persistenceDAO" class="com.blahblah.server.dao.impl.PersistenceDAOImpl" 
parent="abstractDAO"> 
</bean> 

Estos deberían ser las cosas que usted necesita. No tienen que estar en el mismo archivo, tal vez dividirlos entre servicios y daos.

1

Otro punto es comprobar si la base de datos admite la transacción

Cuestiones relacionadas