Spring Transaction - 当一个db更新失败时自动回滚以前的db更新

时间:2010-10-07 10:07:13

标签: java hibernate spring transactions

我正在编写一个简单的应用程序(Spring + Hibernate + PostgreSql db)。我只是想构建一个示例对象并持久存在于db。

我运行一个简单的java类main方法,我已经加载了applicationContext并且引用了服务类,如下所示

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

应用程序上下文 - 上下文:

<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>

在TestService中我注入了TestDao。在测试服务方法中,我构建了员工对象 emp1和emp2并且两次调用dao来更新。

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();
        }
    }

}

当emp2更新失败时,emp1也应该失败。我怎么做。请建议

提前致谢

更新:

感谢Nanda。我试过Declarative交易。但它没有用。 emp1被持久化并且没有回滚eveb第二次dao调用失败。我已经为方法添加了交易建议                                           
                           

测试是否应用了事务通知我将传播更改为“NOT_SUPPORTED”。但是emp1仍然存在。期望是我们应该有Transaction Not Supported类型的异常。请建议。

更新

@seanizer - 感谢您的更新。我甚至尝试过添加
 @Transactional(传播= Propagation.NOT_SUPPORTED)  public void saveEmp(Employee emp)  到那个服务方法。但它没有用。此外,只有当我需要调用一个dao时,迭代集合才能保持良好状态。如果我必须调用两个不同的dao来持久化obj1和obj2-这可能没有帮助。只是为了检查交易是否得到应用我得到了  @Transactional(传播= Propagation.NOT_SUPPORTED)。 但仍然obj1持续存在。 我只是怀疑给出的xml配置/注释是否正确。请检查

<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> 

我正在使用org.springframework.orm.hibernate3.HibernateTransactionManager作为transactionManager。这是对的吗?


更新了

我创建了从RuntimeException扩展的异常类myRuntimeExp,并将相同的方法从Dao方法抛出到service方法。但仍然没有发生回滚。我只是怀疑我是否在applnContext.xml中正确地给出了配置。有人可以帮助我检查是否将交易建议/注释应用于该方法?有没有办法在调试模式下运行它并检查

问题:

我正在使用

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

但它应该是当前会议并且工作正常。

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

5 个答案:

答案 0 :(得分:4)

如果使用声明式事务管理,则可能会丢失大部分样板:

<强> TestDaoImpl:

private SessionFactory sessionFactory;

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

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

您可以使用@Transactional(或xml配置)从服务层控制事务处理

<强> 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);
}

<强>参考:

答案 1 :(得分:4)

默认情况下,Spring仅回滚未经检查的异常。您必须提供 rollback-for attribute并指定您要捕获的异常。


从春天documentation

  

但是,请注意Spring Framework的事务   默认情况下,基础架构代码将标记事务   在运行时回滚,未经检查的异常;也就是说什么时候   抛出的异常是 RuntimeException 的实例或子类。   (错误也将 - 默认情况下 - 导致回滚。)已检查   从事务方法抛出的异常将结果   在正在回滚的交易中。

答案 2 :(得分:2)

在这里,获取这些片段并希望他们会帮助您:

<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>

这些应该是你需要的东西。它们不必在同一个文件中,也可以在服务和daos之间分开。

答案 3 :(得分:1)

您可以将sessionFactory放在TestServiceImpl中并在那里打开会话。

答案 4 :(得分:1)

另一点是检查数据库是否支持事务