Announcement Announcement Module
Collapse
No announcement yet.
Declarative transactions with simple JDBC Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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
    ...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.

    Comment


    • #3
      Just for completeness - could you post the code where you access and call the service.

      Comment


      • #4
        One common problem is using BeanFactory instead of ApplicationContext.
        Last edited by karldmoore; Aug 29th, 2007, 12:12 PM.

        Comment


        • #5
          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.

          Comment


          • #6
            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, 12:12 PM.

            Comment


            • #7
              Why use BeanFactory

              That's a good question. I have been using Spring for about 2 years but always in a Web app context. I just looked at the reference guide, section 3.1, to figure out why I chose BeanFactory.

              Bottom line, I was too hasty and did not read the call out indicating the differences between BeanFactory and ApplicationContext!

              After a read, I wonder if the summarization:

              In short, favor the use of an ApplicationContext.
              Could be more explicit along the lines of
              Choose ApplicationContext as the container representation unless you know BeanFactory will meet your needs.
              Or something - If I'm to the point of suggesting documentation changes then all is lost ;-)

              Comment


              • #8
                Ok, well thanks for the update anyway. I think there has been some updates to this bit of documentation anyway so it might be clearer in the future.
                Last edited by karldmoore; Aug 29th, 2007, 12:12 PM.

                Comment

                Working...
                X