2011-03-30 30 views
2

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

我有两个主要问题:

  1. 设置defaultAutoCommit为false,我们的数据源(其中我们需要为我们的应用程序)会导致所有查询回滚,伴或不参与交易。
  2. 已配置事务并创建代理类以及事务方法,但不会使用任何事务。

第一个问题很复杂,因为每个查询都在数据库中回滚。这也包括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来处理我的连接和查询。

+0

您能告诉我们用于获取服务bean实例的代码以及使用dataSource的某些服务bean的代码吗?特别是,你使用DataSourceUtils.getConnection(DataSource)来获得连接吗?或者你使用JdbcTemplate? – 2011-03-30 20:41:06

+0

感谢您的回复,请参阅所需附加信息的编辑。 – 2011-03-30 21:38:00

回答

3

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

我永远不会怀疑这样的事情是问题,但按照上述链接中列出的步骤完美工作。

里面我派遣-servlet.xml中本来我宣布我的组件扫描如下:

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

这是一个父包我所有的应用程序豆类。因此,正如上面链接所述,Spring使用来自不知道事务的dispatcher-servlet.xml中的服务bean覆盖applicationContext.xml中的事务服务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对象的足印在我的日志文件,这是我的交易正是工作。这也解决了我在数据库中自动回滚的第一个初始问题。我想它一定与缺乏交易密切相关。

+0

''可能会危害您的健康。由于你提到的原因,我避免它。但是+1解释你的解决方案。您应该将自己的答案标记为已接受。 – skaffman 2011-04-01 20:00:00

+0

我在处理注释时需要它的印象。有没有更好的方法来处理这个问题? – 2011-04-01 20:02:03

+0

另外,我必须再等10分钟才能接受我的答案;) – 2011-04-01 20:02:22