Spring Jdbc声明事务已创建但未执行任何操作

时间:2011-03-30 20:11:09

标签: java spring spring-jdbc spring-transactions

我试图在基于Spring的Web应用程序中配置声明式事务管理,但它拒绝与我合作。

我有两个主要问题:

  1. 在我们的dataSource(我们的应用程序需要)上将defaultAutoCommit设置为false会导致所有查询回滚,无论是否涉及事务。
  2. 已配置事务并创建了代理类和事务方法,但似乎没有使用任何事务。
  3. 第一个问题相当令人困惑,因为每个单独的查询都在数据库中回滚。这也包括SELECT语句。什么可能导致每个查询在数据库中回滚?

    至于第二个问题,我的交易管理配置概述如下:

    的applicationContext.xml

    <?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:p="http://www.springframework.org/schema/p"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xmlns:context="http://springframework.org/schema/context"
           xmlns:util="http://www.springframework.org/schema/util"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/spring-context-3.0.xsd
           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"
           default-autowire="byName">
    
    <!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) -->
    <tx:advice id="txAdvice" transaction-manager="txManager">
      <!-- the transactional semantics... -->
      <tx:attributes>
        <!-- other methods use the default transaction settings (see below) -->
        <tx:method name="*" rollback-for="Exception" />
      </tx:attributes>
    </tx:advice>
    
    <!-- ensure that the above transactional advice runs for any execution
     of an operation defined by a service in the service package -->
    <aop:config>
      <aop:pointcut id="serviceOperations" expression="execution(* foo.bar.service.*.*(..))"/>
      <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperations"/>
    </aop:config>
    
    <!-- similarly, don't forget the PlatformTransactionManager -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="defaultAutoCommit" value="false" />
    </bean>
    
    <bean id="fooService" class="foo.bar.service.FooService" />
    
    <bean id="barService" class="foo.bar.service.BarService" />
    
    <bean id="zapService" class="foo.bar.service.ZapService" />
    
    </beans>
    

    在我尝试解决此问题时访问过的所有教程和论坛中,我认为我的配置应该是正确的。但是我并不完全理解aop和spring交易,所以我可能会遗漏一些至关重要的事情。

    如上所述,我可以跟踪我的日志并查看为我的服务类创建的代理以及事务方法。但是,当我实际运行应用程序并跟踪日志时,我没有看到任何处理DataSourceTransactionManager或正在创建,提交,回滚等事务的语句。

    在我看来,实际上没有任何东西在运行,而且我非常困惑,因为我遵循了许多不同的教程并尝试了许多不同的方法,但它总是以这种情况结束。

    我也非常确定我已正确设置log4j属性以接收来自DataSourceTransactionManager的消息,但我在下面提供它们以确保它不仅仅是我的记录错误。

    我的log4j设置了以下记录器,以尝试跟踪事务:

    log4j.logger.org.springframework=INFO, file
    log4j.logger.org.springframework.jdbc.datasource=DEBUG, file
    log4j.logger.org.springframework.transaction=DEBUG, file
    

    注意:我在DEBUG上运行了顶级记录器,这是我验证正在创建服务代理的地方。

    有没有人对可能发生的事情有任何见解?我现在很困惑,因为我确实看到有些部分涉及正在创建的交易,但我没有看到任何交易被使用的任何迹象。

    修改

    JB Nizet要求的其他信息。

    我的整个应用程序都是注释驱动的,所以我的服务bean用@Service注释,并通过基于名称的自动装配注入我的控制器。

    以下是我的一个服务类的示例(名称已更改,但将反映我的applicationContext.xml)。

    @Service("zapService")
    public class ZapService
    {
    
        /**
         * Data access object which performs the database look up
         */
        private ZapDAO zapDAO;
    
        /**
         * Add the given zap to the database
         *
         * @param zap a populated zap
         */
        public void processNewZap(Zap zap)
        {
            zapDAO.processNewZap(zap);
        }
    }
    

    如您所见,我的服务类只是控制器类和dao类之间的代理。 DAO是我实际处理数据库连接的地方。

    我相信我在某个地方阅读过,在处理事务时,使服务事务处理,而不是dao类是首选。如果我错了,请纠正我。

    ZapDAO课程概述如下。

    @Repository("zapDAO")
    public class ZapDAO
    {
    
        /**
         * Log4j logger for this class
         */
        Logger logger = Logger.getLogger(ZapDAO.class);
    
        /**
         * Spring jdbc object to handle interacting with the database
         */
        private JdbcTemplate jdbcTemplate;
    
        public void processNewZap(Zap zap) {
    
            ... query constructing logic ...
    
            this.jdbcTemplate.update(INSERT_ZAP_QUERY_SQL);
    
        }
    
        public void setDataSource(DataSource dataSource)
        {
            Assert.notNull(dataSource, "You must supply a valid data source");
    
            this.jdbcTemplate = new JdbcTemplate(dataSource);
        }
    }
    

    我使用jdbcTemplate来处理我的连接和查询。

1 个答案:

答案 0 :(得分:3)

因此,经过几个小时的搜索,调试和撕掉我的头发,我终于偶然发现了this小宝石,提供了所有的答案。

我从来不会怀疑这样的问题,但是按照上述链接中列出的步骤完美地工作了。

在我的dispatch-servlet.xml中,我最初声明了我的组件扫描,如下所示:

<context:component-scan base-package="foo.bar"/>

这是我所有应用程序bean的父包。因此,如上面的链接所述,Spring使用来自dispatcher-servlet.xml的服务bean从applicationContext.xml覆盖我的事务服务bean,该服务bean不知道事务。

我所做的就是打破上面的组件扫描,只扫描包含非事务bean的文件夹。

<context:component-scan base-package="foo.bar.controller"/>
<context:component-scan base-package="foo.bar.model"/>
<context:component-scan base-package="foo.bar.service.display"/>
<context:component-scan base-package="foo.bar.service.security"/>

<!-- foo.bar.service gets scanned in applicationContext.xml and includes 
transactions so we must make sure to not include it here. The transactional beans
will be overridden in that case -->

在此之后,我的交易完全符合预期,我终于在日志文件中看到了交易和DataSourceTransactionManager的足迹。这也解决了我在数据库中自动回滚的第一个初始问题。我想它一定与缺乏交易密切相关。

相关问题