不从ZK回滚Spring事务

时间:2015-05-27 15:26:53

标签: spring hibernate zk

我在调用Spring Sevice中编写的服务方法时遇到问题,该方法是在MVVM中注入的,我保存了一个对象,之后做了一些其他的值胖方法调用,抛出异常,我希望在抛出异常时例外我的事务回滚我的服务方法部分在CeilingServiceIMPL下面:

    CeilingSheet ceilingSheet = new CeilingSheet();
    ceilingSheet.setFiscalYear(fiscalYear);
    ceilingSheet.setStatus(ECeilingSheetStatus.NEW);
    ceilingSheet = saveCeilingSheet(ceilingSheet).getResult();

    CeilingCategory ceilingCategory1 = null;
    try {
        ceilingCategory1 = categoryQueryService.findCeilingCategoryByCode(
                "01").getResult();
    } catch (ObjectNotFoundException ex) {
        throw new RequestException(1234, ceilingCategory1);
    }

如果抛出RequestException,我希望我之前保存的记录也会回滚。我通过注释为

制作服务交易
@Transactional(rollbackFor =  RequestException.class)

注入豆

@WireVariable(ICeilingSheetService.NAME) private ICeilingSheetService ceilingSheetService;

当我尝试使用此方法从junit测试用例调用时,它可以很好地回滚,但是当我将它与ZK zul页面和View模型通过自动服务集成时,它会停止回滚,即使我的代码抛出RequestException,我的CeilingSheet仍然存在。 我的ZK web.xml是

    <!-- Spring can be easily integrated into any Java-based web framework. 
    All you need to do is to declare the ContextLoaderListener in your web.xml 
    and use a contextConfigLocation <context-param> to set which context files 
    to load. If you don't specify the contextConfigLocation context parameter, 
    the ContextLoaderListener will look for a /WEB-INF/applicationContext.xml 
    file to load. Once the context files are loaded, Spring creates a WebApplicationContext 
    object based on the bean definitions and puts it into the ServletContext. -->

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
             /WEB-INF/application-context.xml
     </param-value>
</context-param>

<!-- LOGGER -->
<context-param>
    <param-name>log4j-config-location</param-name>
    <param-value>WEB-INF/log4j.properties</param-value>
</context-param>

<!-- Loads the Spring web application context -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- end of spring configuration -->

<description><![CDATA[My ZK Application]]></description>
<display-name>IFMIS User Interface</display-name>

<!-- //// -->
<!-- ZK -->
<listener>
    <description>ZK listener for session cleanup</description>
    <listener-class>org.zkoss.zk.ui.http.HttpSessionListener</listener-class>
</listener>
<servlet>
    <description>ZK loader for ZUML pages</description>
    <servlet-name>zkLoader</servlet-name>
    <servlet-class>org.zkoss.zk.ui.http.DHtmlLayoutServlet</servlet-class>

    <!-- Must. Specifies URI of the update engine (DHtmlUpdateServlet). It 
        must be the same as <url-pattern> for the update engine. -->
    <init-param>
        <param-name>update-uri</param-name>
        <param-value>/zkau</param-value>
    </init-param>
    <!-- Optional. Specifies whether to compress the output of the ZK loader. 
        It speeds up the transmission over slow Internet. However, if you configure 
        a filter to post-processing the output, you might have to disable it. Default: 
        true <init-param> <param-name>compress</param-name> <param-value>true</param-value> 
        </init-param> -->
    <!-- [Optional] Specifies the default log level: OFF, ERROR, WARNING, INFO, 
        DEBUG and FINER. If not specified, the system default is used. <init-param> 
        <param-name>log-level</param-name> <param-value>OFF</param-value> </init-param> -->
    <load-on-startup>1</load-on-startup><!-- Must -->
</servlet>
<servlet-mapping>
    <servlet-name>zkLoader</servlet-name>
    <url-pattern>*.zul</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>zkLoader</servlet-name>
    <url-pattern>*.zhtml</url-pattern>
</servlet-mapping>
<!-- [Optional] Uncomment it if you want to use richlets. <servlet-mapping> 
    <servlet-name>zkLoader</servlet-name> <url-pattern>/zk/*</url-pattern> </servlet-mapping> -->
<servlet>
    <description>The asynchronous update engine for ZK</description>
    <servlet-name>auEngine</servlet-name>
    <servlet-class>org.zkoss.zk.au.http.DHtmlUpdateServlet</servlet-class>

    <!-- [Optional] Specifies whether to compress the output of the ZK loader. 
        It speeds up the transmission over slow Internet. However, if your server 
        will do the compression, you might have to disable it. Default: true <init-param> 
        <param-name>compress</param-name> <param-value>true</param-value> </init-param> -->
    <!-- [Optional] Specifies the AU extension for particular prefix. <init-param> 
        <param-name>extension0</param-name> <param-value>/upload=com.my.MyUploader</param-value> 
        </init-param> -->
</servlet>
<servlet-mapping>
    <servlet-name>auEngine</servlet-name>
    <url-pattern>/zkau/*</url-pattern>
</servlet-mapping>

我的application-context.xml

<bean
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>/WEB-INF/database.properties</value>
            <value>/WEB-INF/msg-database.properties</value>
        </list>
    </property>
</bean>

<tx:annotation-driven />

<context:annotation-config />


<context:component-scan base-package="my.service" />

<import resource="hibernate-context.xml" />

我的hibernat-context.xml

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass">
        <value>${jdbc.driverClassName}</value>
    </property>
    <property name="jdbcUrl">
        <value>${jdbc.url}</value>
    </property>
    <property name="user">
        <value>${jdbc.username}</value>
    </property>
    <property name="password">
        <value>${jdbc.password}</value>
    </property>
    <property name="maxPoolSize" value="${jdbc.maxPoolSize}" />
    <property name="minPoolSize" value="${jdbc.minPoolSize}" />
    <property name="maxStatements" value="${jdbc.maxStatements}" />
    <property name="testConnectionOnCheckout" value="${jdbc.testConnection}" />
</bean>

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

<bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan">
        <list>
            <value>my.domain.class</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">${hibernate.dialect}</prop>
            <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
            <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
            <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
            <prop key="jadira.usertype.autoRegisterUserTypes">${jadira.usertype}</prop>
        </props>
    </property>
</bean>
<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<bean id="persistenceExceptionTranslationPostProcessor"
    class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

请建议......

2 个答案:

答案 0 :(得分:0)

此类情况的第一步始终是为DEBUG启用级别org.springframework.orm.hibernate4.HibernateTransactionManager的日志记录。这将向您展示Spring正在做什么以及为什么。

例如,它会在检测到异常时以及何时执行回滚或提交时向您显示。您还可以在此代码中设置断点以查看正在发生的情况。这很简单。

了解一下ZK,我的猜测是你在ZK代码的某处有new CeilingServiceIMPL(),因为你无法弄清楚如何将Spring bean注入控制器。这有效地使所有@Transactional无用。

你必须从春天拿到豆子。查看http://www.zkoss.org/product/zkspring以及Using Spring Variable Resolver处的文档如何使用ZK连接bean。

答案 1 :(得分:0)

我找到了解决方案: 原因:在我的应用程序中,我们需要根据异常抛出的数字显示User消息,为此我们有一个单独的message-hibernate-context.xml文件,单独使用

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

,其中一个已经使用了hibernate-context.xml

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

以上两个xml文件从我的application-context.xml调用为

<import resource="hibernate-context.xml" />
<import resource="message-hibernate-context.xml" />

因此,在代码抛出基于键抛出的异常之后,我的用户消息bean试图加载单独的事务管理器和旧事务提交,并且新的Hibernate会话启动即将回滚,因为这是新的事务所以它没有找到任何东西回滚。

删除其他事务管理器后,它就开始工作了。 谢谢大家的支持......