Announcement Announcement Module
Collapse
No announcement yet.
AOP and TransactionManager can I stop this? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • AOP and TransactionManager can I stop this?

    Hi

    Here's my situation.

    We have an app (Tomcat 5.5.9A, Spring 2.0.5 (commons dbcp), MySQL 5.1?, iBatis 2.3.0.667 ) with AOP declarative transaction control - Here's the xml:

    DAOs
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
    
    	<!-- ========================= PERSISTENCE DEFINITIONS ========================= -->
    
    <beans>
    
      <!-- DataSource Beans - These are grbbed from tomcat using jndi lookups -->
      <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean" scope="singleton" abstract="false" lazy-init="default" autowire="default" dependency-check="default">
           <property name="jndiName" value="java:comp/env/jdbc/newDBIssues" /> 
      </bean>
    
      <!-- IBatis Map configuration -->
      <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
        <property name="configLocation" value="WEB-INF/sqlmap-context.xml"/>
        <property name="dataSource" ref="dataSource"/>
      </bean>
      <bean id="creditSqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
        <property name="configLocation" value="WEB-INF/credit-sqlmap-context.xml"/>
        <property name="dataSource" ref="creditDataSource"/>
      </bean>
      
      <!-- DAOs here -->
    
       <bean id="ProspectusFieldDAO" class="com.globalfilings.domain.dao.ProspectusFieldDAOImpl">
      	<property name="sqlMapClient" ref="sqlMapClient"/>
      	<property name="fieldCache" ref="fieldCache"/>
      </bean>	
      
    
    </beans>
    Services:

    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">
    
    	<!-- Transaction Managers -->
    	<bean id="txManager"
    		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    		<property name="dataSource" ref="dataSource" />
    	</bean>
    
    	<!-- Services beans  -->
    	<bean id="issuesServices" class="com.globalfilings.services.IssuesServices">
    		<property name="prospectusFieldDAO" ref="ProspectusFieldDAO"/>
    	</bean>
    	
    	<!-- AOP Enables transaction options -->
    	<!-- the transactional advice (i.e. what 'happens'; see the <aop:advisor/> bean below) -->
    	<tx:advice id="issuesTxAdvice" transaction-manager="txManager">
    		<!-- the transactional semantics... -->
    		<tx:attributes>
    			<!-- all methods starting with 'select' are read-only -->
    			<tx:method name="select*" read-only="true" propagation="REQUIRED"/>
    			<tx:method name="get*" read-only="true" propagation="REQUIRED"/>
    			<tx:method name="savePagePosition" propagation="REQUIRED" />
    			<tx:method name="save*" propagation="REQUIRED" />
    			<tx:method name="delete*" propagation="REQUIRED" />
    			<tx:method name="revert*" propagation="REQUIRED" />
    			<!-- other methods use the default transaction settings (see below) -->
    			<tx:method name="*" />
    		</tx:attributes>
    	</tx:advice>
    
    	<!-- ensure that the above transactional advice runs for any execution
    		of an operation defined by the service interfaces -->
    	<aop:config>
    		<aop:pointcut id="issuesServiceOperation" expression="execution(* com.globalfilings.services.IIssuesServices.*(..))" />
    		<aop:advisor advice-ref="issuesTxAdvice" pointcut-ref="issuesServiceOperation" />
    	</aop:config>
    	<aop:config>
    		<aop:pointcut id="userServiceOperation"	expression="execution(* com.globalfilings.services.IUserServices.*(..))" />
    		<aop:advisor advice-ref="creditTxAdvice" pointcut-ref="userServiceOperation" />
    	</aop:config>
    	
    </beans>
    I've removed some of the beans from the xml for clarity.
    Here's the problem - in the course of a request there is an interceptor that look up some values using a method of ProspectusFieldDAOImpl - Here it is:

    Code:
    public ProspectusField selectByPrimaryKey(Integer id) {
        	ProspectusField record = null;
        	//Look in the cache first
        	Element cacheResult = null;
    		cacheResult = fieldCache.get(id);
    		if(cacheResult==null){
    			//No cache so go to the db	
    	    	ProspectusField key = new ProspectusField();
    	        key.setId(id);
    	        record = (ProspectusField) getSqlMapClientTemplate().queryForObject("wf_Prospectus_Fields2.abatorgenerated_selectByPrimaryKey", key);
    	        //check to see if we have valid field
    	        if(record!=null){
    	        	//Yes so stick it on the cache
    	        	fieldCache.put(new Element(id, record));
    	        }
    		}else{
    			record = (ProspectusField)cacheResult.getValue();
    		}
            return record;
        }
    This pulls stuff out of the cache as expected but it doesn't save much time (2-10ms per lookup). I put debug onto Transaction Manager and it is still pulling connections from the pool and doing full transaction management even though it doesn't run the select - here's a snippet of the log when the cache works:

    Code:
    2007-08-16 11:46:15,781 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Using transaction object [org.springframework.jdbc.datasource.DataSourceTransactionManager$DataSourceTransactionObject@8b915d]>
    2007-08-16 11:46:15,781 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Creating new transaction with name [com.globalfilings.services.IIssuesServices.getFieldbyId]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly>
    2007-08-16 11:46:15,812 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Acquired Connection [org.apache.tomcat.dbcp.dbcp.PoolableConnection@8777c] for JDBC transaction>
    2007-08-16 11:46:15,812 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Switching JDBC Connection [org.apache.tomcat.dbcp.dbcp.PoolableConnection@8777c] to manual commit>
    2007-08-16 11:46:15,843 INFO [com.globalfilings.services.IssuesServices] - <Returning field 370 took 0ms>
    2007-08-16 11:46:15,843 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Triggering beforeCommit synchronization>
    2007-08-16 11:46:15,843 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Triggering beforeCompletion synchronization>
    2007-08-16 11:46:15,843 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Initiating transaction commit>
    2007-08-16 11:46:15,843 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Committing JDBC transaction on Connection [org.apache.tomcat.dbcp.dbcp.PoolableConnection@8777c]>
    2007-08-16 11:46:15,859 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Triggering afterCommit synchronization>
    2007-08-16 11:46:15,874 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Triggering afterCompletion synchronization>
    2007-08-16 11:46:15,906 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Releasing JDBC Connection [org.apache.tomcat.dbcp.dbcp.PoolableConnection@8777c] after transaction>
    I suppose this means that all is working just as designed but is there any way I can stop the Transaction doing it's stuff? The log snippet details just one of the lookups but the interceptor could make up to 20 which may add 2 seconds to the processing.

    Any ideas?

    Thanks

    Charlie

  • #2
    One way to prevent it would be to have all the AOP at the same level, you could then apply ordering.

    Comment


    • #3
      thanks karldmoore - not sure what you meant though as I'm hard of understanding

      Sorted it in the end by pulling new methods to access the cache from the DAO up to the Services layer, prefixing these methods with cache (eg cacheGetSomethingById(Integer ID) including the one called from the Interceptor. The getGetSomethingById(Integer ID) now all go to the db and the tx:advice advice now look like this:

      Code:
      <tx:advice id="issuesTxAdvice" transaction-manager="txManager">
      		<!-- the transactional semantics... -->
      		<tx:attributes>
      			<tx:method name="cache*" propagation="NEVER"/>
      			<tx:method name="select*" read-only="true" propagation="REQUIRED"/>
      			<tx:method name="get*" read-only="true" propagation="REQUIRED"/>
      			<tx:method name="savePagePosition" propagation="REQUIRED" />
      			<tx:method name="save*" propagation="REQUIRED" />
      			<tx:method name="delete*" propagation="REQUIRED" />
      			<tx:method name="revert*" propagation="REQUIRED" />
      			<tx:method name="*" />
      		</tx:attributes>
      	</tx:advice>
      TransactionManager no longer takes any time:
      Code:
      2007-08-16 15:38:20,361 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Using transaction object [org.springframework.jdbc.datasource.DataSourceTransactionManager$DataSourceTransactionObject@5f4e03]>
      2007-08-16 15:38:20,361 INFO [com.globalfilings.services.IssuesServices] - <Returning field 1 took 0ms>
      2007-08-16 15:38:20,361 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Triggering beforeCommit synchronization>
      2007-08-16 15:38:20,361 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Triggering beforeCompletion synchronization>
      2007-08-16 15:38:20,361 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Triggering afterCommit synchronization>
      2007-08-16 15:38:20,361 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Triggering afterCompletion synchronization>
      and all is faster than snakes now - Hooray!

      Comment


      • #4
        Glad you've sorted it! What I meant was, if you are using an interceptor for the cache and you are also using a transactional interceptor then these would need to both be at the same level e.g. the service layer. You could then order the proxies to ensure the cache was called first and then the transactional interceptor. This was you'd never create a trasaction in the cache was hit.
        http://www.springframework.org/docs/...dvice-ordering
        Last edited by karldmoore; Aug 27th, 2007, 03:01 PM.

        Comment

        Working...
        X