首页 文章

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

提问于
浏览
5

我正在编写一个简单的应用程序(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也应该失败 . 我怎么做 . 请指教

提前致谢

更新 :

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

为了测试是否应用了交易建议我将传播更改为“NOT_SUPPORTED” . 但是emp1仍然存在 . 期望是我们应该有Transaction Not Supported类型的异常 . 请指教 .

更新

@seanizer - 感谢您的更新 . 我甚至尝试过添加
@Transactional(propagation = Propagation.NOT_SUPPORTED)public void saveEmp(Employee emp)到该服务方法 . 但它没有用 . 此外,只有当我需要调用一个dao时,迭代集合才能保持良好状态 . 如果我必须调用两个不同的dao来持久化obj1和obj2-这可能没有帮助 . 为了检查交易是否得到应用,我得到@Transactional(propagation = 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 ,它工作正常 .

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

5 回答

  • 1

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

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

    Reference:

  • 4

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


    从 Spring 天documentation

    但是,请注意,默认情况下,Spring Framework的事务基础结构代码仅在运行时未经检查的异常情况下标记事务以进行回滚;也就是说,抛出的异常是RuntimeException的实例或子类 . (错误也将 - 默认情况下 - 导致回滚 . )从事务方法抛出的已检查异常不会导致事务回滚 .

  • 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之间分开 .

  • 1

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

  • 4

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

相关问题