Announcement Announcement Module
Collapse
No announcement yet.
iBatis lazy load transaction issues. Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • iBatis lazy load transaction issues.

    Hi forum,

    I'm having a problem with ibatis plus lazy load when I'm dealing with transactions managed by Spring. If I have a transaction initialized by Spring, everything goes fine until I try to use lazy load, because Lazy Load uses the dataSource defined on iBatis xml configuration file. I'll post my solution so you can comment it, use it or tell me if there is another way to do that.

    If I just define a dataSource at spring, LazyLoad won't work, because iBatis won't find a dataSource (I'll get a NullPointerException. This is a know problem, here: http://forum.springframework.org/viewtopic.php?t=3076).

    Here is an example of the problem:
    I have an object called User. This object has a collection of attributes named roles, accessed by the method getRoles(). This collection of attributes is configured to use Lazy Load.

    If I do the following sequence of operation:
    Code:
    	roles = new ArrayList();
    	roles.add(manager);
    	dao.insertRoles(roles, "mortadela");
    	user = dao.getUser("mortadela");
    	roles = user.getRoles();

    The list referenced by the variable roles does not have the newly added role. This is a transaction issue because iBatis does not use the sabe dataSource and transaction manager that spring does.

    Here is my solution.

    At dataAccessContext-local.xml I define the following dataSource, transactionManager and sqlMapClientFactory.

    Code:
    	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    		<property name="driverClassName"><value>$&#123;jdbc.driverClassName&#125;</value></property>
    		<property name="url"><value>$&#123;jdbc.url&#125;</value></property>
    		<property name="username"><value>$&#123;jdbc.username&#125;</value></property>
    		<property name="password"><value>$&#123;jdbc.password&#125;</value></property>
    	</bean>
    
    	<bean id="dataSourceIbatis" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
    		<property name="targetDataSource"><ref local="dataSource"/></property>
    	</bean>
    
    	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    		<property name="dataSource"><ref local="dataSource"/></property>
    	</bean>
    
    	<!-- SqlMap setup for iBATIS Database Layer -->
    	<bean id="sqlMapClient" class="br.com.gwe.dao.ibatis.BarbaSqlMapClient">
    		<property name="configLocation"><value>WEB-INF/sql-map-config.xml</value></property>
    		<property name="dataSource"><ref local="dataSourceIbatis"/></property>
    		<property name="concurrentTransactions"><value>20</value></property>
    	</bean>
    And, here is the code for the BarbaSqlMapClient. Barba is the name of my application.

    Code:
    public class BarbaSqlMapClient extends SqlMapClientFactoryBean &#123;
    	private DataSource dataSource;
    	private int concurrentTransactions;
    	private ExtendedSqlMapClient sqlClient = null;
    
    	/**
    	 * @see org.springframework.orm.ibatis.SqlMapClientFactoryBean#getObject&#40;&#41;
    	 */
    	public synchronized Object getObject&#40;&#41; &#123;
    		if &#40;sqlClient == null&#41; &#123;
    			sqlClient = &#40;ExtendedSqlMapClient&#41; super.getObject&#40;&#41;;
    			SqlMapExecutorDelegate delegate = sqlClient.getDelegate&#40;&#41;;
    			if &#40;delegate.getTxManager&#40;&#41; == null&#41; &#123;
    				delegate.setTxManager&#40;createTxManager&#40;&#41;&#41;;
    			&#125;
    		&#125;
    		return sqlClient;
    	&#125;
    	
    	/**
    	 * Create a new TransactionManager, so iBatis use our DataSource,
    	 * instead of a new one defined on a XML.
    	 * @return
    	 */
    	private TransactionManager createTxManager&#40;&#41; &#123;
    		JdbcTransactionConfig config = new JdbcTransactionConfig&#40;&#41;;
    		config.setDataSource&#40;dataSource&#41;;
    		config.setMaximumConcurrentTransactions&#40;concurrentTransactions&#41;;
    		TransactionManager txManager = new TransactionManager&#40;config&#41;;
    		return txManager;
    	&#125;
    
    	/*
    	 * getters and setters.
    	 */
    	
    	public DataSource getDataSource&#40;&#41; &#123;
    		return dataSource;
    	&#125;
    	public void setDataSource&#40;DataSource dataSource&#41; &#123;
    		this.dataSource = dataSource;
    	&#125;
    	public int getConcurrentTransactions&#40;&#41; &#123;
    		return concurrentTransactions;
    	&#125;
    	public void setConcurrentTransactions&#40;int concurrentTransactions&#41; &#123;
    		this.concurrentTransactions = concurrentTransactions;
    	&#125;
    &#125;
    Is this solution good? Any suggestions?

    Thanks.

  • #2
    fixed!

    I upgrated my aplication to spring 1.2.1 and the default implementation of SqlMapClientFactoryBean is working with lazy load + transactions now.

    Thanks!

    Comment


    • #3
      Pedido de contato

      oi efpiva,

      Estou com esse mesmo problema e apesar de atualizar para o spring 1.2.1, continua dando o mesmo erro.
      Será que podias dar o teu contato para trocar-mos emails pois preciso de resolver o problema ?

      Grato,
      Paulo

      Comment


      • #4
        Olá Paulo. Me chamo Eduardo Piva. Meu email é:

        eduardo arroba gwe ponto com ponto br.

        Ou

        efpiva arroba gmail ponto com

        Mascarei o email para evitar spam.

        Abraços.

        Comment

        Working...
        X