Results 1 to 8 of 8

Thread: Declarative transactions with simple JDBC

Hybrid View

  1. #1
    Join Date
    Dec 2005
    Posts
    16

    Default Declarative transactions with simple JDBC

    Yes, another person with transaction "issues". I am missing something basic as the logging, below, does not indicate the configured DataSourceTransactionManager is instantiated or used.

    I have attempted to carefully follow the chapter 9 reference guide details as I really would like to use this new AOP based method for transaction demarcation.

    Although this is another newbie, basic setup, any help debugging this sample config would be appreciated.

    The goal: write to an Oracle global temp table in one DAO method and read the data from another DAO. Configure a service method to call both in a transaction which sets autocommit=false and does not commit until the method ends - as desired.

    I have tried the xml based and @Transaction annotation based methods with the same results.

    Spring config:
    Code:
    <?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:aop="http://www.springframework.org/schema/aop" 
        xmlns:tx="http://www.springframework.org/schema/tx" 
        xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd 
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd 
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
    
      <bean id="ds" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
        <property name="url" value="jdbc:oracle:thin:@localhost:1522:xe"/>
        <property name="username" value="*"/>
        <property name="password" value="*"/>
      </bean>
    
      <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="ds" /> 
      </bean>
    
      <bean id="transDao" class="apps.test.TransDaoImpl">
        <property name="dataSource" ref="ds"/>
      </bean>
      
      <!-- this is the service object that we want to make transactional -->
      <bean id="transService" class="apps.test.TransService">
        <property name="transDao" ref="transDao"/>
      </bean>
    
      <!-- the transactional advice (i.e. what 'happens'; see the <aop:advisor/> bean below) -->
      <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
          <!-- method starting with do* use the default transaction settings (see below) -->
          <tx:method name="do*"/>
        </tx:attributes>
      </tx:advice>
      
      <!-- ensure that the above transactional advice runs for any execution
          of an operation defined by the FooService interface -->
      <aop:config>
        <aop:pointcut id="transServiceOperation" expression="execution(* apps.test.TransService.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="transServiceOperation"/>
      </aop:config>
      
    </beans>
    Here is the Dao and the Service bean:

    Code:
    public interface TransDao {
        public void createData(Integer count);
        public Integer countData();
    }
    
    ---
    
    package apps.test;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    public class TransService {
        
        protected final Log logger = LogFactory.getLog(getClass());
    
        private TransDao transDao;
        
        public void setTransDao(TransDao transDao){
            this.transDao = transDao;
        }
        
        public void doService() {
            transDao.createData(5);
            
            logger.info("Second call count: " + transDao.countData());
        }
    }
    And the debug level log data snippet:
    Code:
    16:16:18  INFO (XmlBeanDefinitionReader.java:293) - Loading XML bean definitions from file [C:\JDeveloper\mywork\springtest\transman\classes\beans.xml]
    16:16:18 DEBUG (DefaultDocumentLoader.java:73) - Using JAXP provider [com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl]
    16:16:18 DEBUG (PluggableSchemaResolver.java:124) - Found XML schema [http://www.springframework.org/schema/beans/spring-beans-2.0.xsd] in classpath: org/springframework/beans/factory/xml/spring-beans-2.0.xsd
    16:16:18 DEBUG (PluggableSchemaResolver.java:124) - Found XML schema [http://www.springframework.org/schema/tx/spring-tx-2.0.xsd] in classpath: org/springframework/transaction/config/spring-tx-2.0.xsd
    16:16:18 DEBUG (PluggableSchemaResolver.java:124) - Found XML schema [http://www.springframework.org/schema/aop/spring-aop-2.0.xsd] in classpath: org/springframework/aop/config/spring-aop-2.0.xsd
    16:16:18 DEBUG (DefaultNamespaceHandlerResolver.java:110) - Loaded mappings [{http://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler, http://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler, http://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler, http://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler, http://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler, http://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler}]
    16:16:19 DEBUG (DefaultBeanDefinitionDocumentReader.java:84) - Loading bean definitions
    16:16:19 DEBUG (DefaultSingletonBeanRegistry.java:152) - Creating shared instance of singleton bean 'transService'
    16:16:19 DEBUG (AbstractAutowireCapableBeanFactory.java:342) - Creating instance of bean 'transService' with merged definition [Root bean: class [apps.test.TransService]; scope=singleton; abstract=false; lazyInit=false; autowireCandidate=true; autowireMode=0; dependencyCheck=0; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [C:\JDeveloper\mywork\springtest\transman\classes\beans.xml]]
    16:16:19 DEBUG (AbstractAutowireCapableBeanFactory.java:393) - Eagerly caching bean 'transService' to allow for resolving potential circular references
    16:16:19 DEBUG (DefaultSingletonBeanRegistry.java:152) - Creating shared instance of singleton bean 'transDao'
    16:16:19 DEBUG (AbstractAutowireCapableBeanFactory.java:342) - Creating instance of bean 'transDao' with merged definition [Root bean: class [apps.test.TransDaoImpl]; scope=singleton; abstract=false; lazyInit=false; autowireCandidate=true; autowireMode=0; dependencyCheck=0; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [C:\JDeveloper\mywork\springtest\transman\classes\beans.xml]]
    16:16:19 DEBUG (AbstractAutowireCapableBeanFactory.java:393) - Eagerly caching bean 'transDao' to allow for resolving potential circular references
    16:16:19 DEBUG (DefaultSingletonBeanRegistry.java:152) - Creating shared instance of singleton bean 'ds'
    16:16:19 DEBUG (AbstractAutowireCapableBeanFactory.java:342) - Creating instance of bean 'ds' with merged definition [Root bean: class [org.apache.commons.dbcp.BasicDataSource]; scope=singleton; abstract=false; lazyInit=false; autowireCandidate=true; autowireMode=0; dependencyCheck=0; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=close; defined in file [C:\JDeveloper\mywork\springtest\transman\classes\beans.xml]]
    16:16:19 DEBUG (AbstractAutowireCapableBeanFactory.java:393) - Eagerly caching bean 'ds' to allow for resolving potential circular references
    16:16:19 DEBUG (JdbcTemplate.java:736) - Executing prepared SQL update
    16:16:19 DEBUG (JdbcTemplate.java:520) - Executing prepared SQL statement [insert into xcc_test (data_id) values (?)]
    16:16:19 DEBUG (DataSourceUtils.java:112) - Fetching JDBC Connection from DataSource
    16:16:21 DEBUG (StatementCreatorUtils.java:135) - Setting SQL statement parameter value: column index 1, parameter value [1], value class [java.lang.Integer], SQL type unknown
    16:16:21 DEBUG (JdbcTemplate.java:746) - SQL update affected 1 rows
    16:16:21 DEBUG (DataSourceUtils.java:312) - Returning JDBC Connection to DataSource
    16:16:21 DEBUG (JdbcTemplate.java:736) - Executing prepared SQL update
    16:16:21 DEBUG (JdbcTemplate.java:520) - Executing prepared SQL statement [insert into xcc_test (data_id) values (?)]
    16:16:21 DEBUG (DataSourceUtils.java:112) - Fetching JDBC Connection from DataSource
    16:16:21 DEBUG (StatementCreatorUtils.java:135) - Setting SQL statement parameter value: column index 1, parameter value [2], value class [java.lang.Integer], SQL type unknown
    16:16:21 DEBUG (JdbcTemplate.java:746) - SQL update affected 1 rows
    16:16:21 DEBUG (DataSourceUtils.java:312) - Returning JDBC Connection to DataSource
    ...
    16:16:21  INFO (TransService.java:19) - Second call count: 0
    I would expect (and like!) a transaction to be started around "doService()" method call but only see the connection being returned to the pool - which does a commit each time I assume.

    Any thoughts?
    Thanks.

  2. #2
    Join Date
    Dec 2005
    Posts
    16

    Default ...more info

    I changed the TransService to an interface but that did nothing.

    Further, adding this check - as suggested in a prior thread:
    Code:
    TransactionAspectSupport.currentTransactionStatus().isNewTransaction();
    not surprisingly caused this:
    Code:
    17:30:54 DEBUG (AbstractBeanFactory.java:203) - Returning cached instance of singleton bean 'ds'
    Exception in thread "main" org.springframework.transaction.NoTransactionException: No transaction aspect-managed TransactionStatus in scope
    	at org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus(TransactionAspectSupport.java:107)
    	at apps.test.TransServiceImpl.doService(TransServiceImpl.java:33)
    	at apps.test.Boot.go(Boot.java:19)
    	at apps.test.Boot.main(Boot.java:11)
    Process exited with exit code 1.

  3. #3
    Join Date
    Aug 2004
    Posts
    1,110

    Default

    Just for completeness - could you post the code where you access and call the service.
    Thomas Risberg
    SpringSource by Pivotal
    http://www.springsource.org

  4. #4
    Join Date
    Sep 2006
    Location
    UK
    Posts
    8,424

    Default

    One common problem is using BeanFactory instead of ApplicationContext.
    Last edited by karldmoore; Aug 29th, 2007 at 11:12 AM.
    Barracuda Networks SSL VPN Lead Developer
    http://pramatr.wordpress.com
    http://twitter.com/karldmoore
    http://www.linkedin.com/in/karldmoore
    Any postings are my own opinion, and should not be attributed to my employer or clients.

  5. #5
    Join Date
    Dec 2005
    Posts
    16

    Default Solved

    That was it - Thanks. As per doc only ApplicationContext is AOP aware. My prior efforts starting from a web app base would not have made me understand this difference.

    My take away is even a "basic" stand alone app should start with an ApplicationContext derived container.

  6. #6
    Join Date
    Sep 2006
    Location
    UK
    Posts
    8,424

    Default

    Fanstastic, glad it's now working. Just out of interest, what made you choose BeanFactory in the first place? This is quite a common problem so I just wondered.
    Last edited by karldmoore; Aug 29th, 2007 at 11:12 AM.
    Barracuda Networks SSL VPN Lead Developer
    http://pramatr.wordpress.com
    http://twitter.com/karldmoore
    http://www.linkedin.com/in/karldmoore
    Any postings are my own opinion, and should not be attributed to my employer or clients.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •