Results 1 to 5 of 5

Thread: Problem with transactions using Spring+Hibernate

  1. #1
    Join Date
    Dec 2004
    Posts
    3

    Default Problem with transactions using Spring+Hibernate

    Hello,

    I'm currently having a problem having a transaction span over two Dao method calls. Allow me to post relevant parts of the application context XML and code to illustrate what I have going on right now.

    The Datasource:

    Code:
    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
      <property name="jndiName"><value>java&#58;comp/env/jdbc/BrewerfanDB</value></property>
    </bean>
    The Session Factory:

    Code:
    	<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
    		<property name="dataSource"><ref local="dataSource"/></property>
    		<property name="mappingResources">
    		  <list>
    						<value>net/brewerfan/bizmodel/article/LinkedArticle.hbm.xml</value>
    			<value>net/brewerfan/bizmodel/common/Player.hbm.xml</value>
    				      </list>
    		</property>
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</prop>
    			</props>
    		</property>
    	</bean>
    The Transaction Manager:

    Code:
    	
    	<bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
    		<property name="sessionFactory"><ref local="sessionFactory"/></property>
    	</bean>
    The transaction properties I wish to use:

    Code:
        <bean id="matchAllWithPropReq" 
            class="org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource">
          <property name="transactionAttribute"><value>PROPAGATION_REQUIRED</value></property>
        </bean>
    My Transaction Interceptor:

    Code:
    	<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
    		<property name="transactionManager"><ref local="transactionManager"/></property>
    		<property name="transactionAttributeSource">
    			<ref bean="matchAllWithPropReq"/>
    		</property>
    	</bean>
    My AutoProxyCreator, since I wish to have ALL method calls on all Service and Dao objects use the same transaction given a particular client call:

    Code:
        <bean id="autoProxyCreator" 
            class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
          <property name="interceptorNames">
            <list>
              <idref local="transactionInterceptor"/>
            </list>
          </property>
          <property name="beanNames">
            <list>
              <value>*Dao</value>
              <value>*Service</value>
            </list>
          </property>
        </bean>
    My Daos:

    Code:
    	<bean id="linkedArticleDao" class="net.brewerfan.dao.article.hibernate.LinkedArticleHibernateDaoImpl">
    		<property name="sessionFactory"><ref local="sessionFactory"/></property>
    	</bean>
    	<bean id="playerDao" class="net.brewerfan.dao.common.hibernate.PlayerHibernateDaoImpl">
    		<property name="sessionFactory"><ref local="sessionFactory"/></property>
    	</bean>
    My Service Object:

    Code:
    	<bean id="articleService" class="net.brewerfan.dao.article.ArticleService">
    		<property name="linkedArticleDao"><ref local="linkedArticleDao"/></property>
    		<property name="playerDao"><ref local="playerDao"/></property>
    	</bean>
    I have a base Dao implementation I use and extend with all my Daos:

    Code:
    public abstract class AbstractBrewerfanHibernateDao extends HibernateDaoSupport &#123;
    
    	protected abstract Class getPersistentClass&#40;&#41;;
    
    	public List findAll&#40;&#41; throws DataAccessException &#123;
    		return &#40;getLocalTemplate&#40;&#41;.find&#40;"from "
    				+ getPersistentClass&#40;&#41;.getName&#40;&#41;&#41;&#41;;
    	&#125;
    
    	public Entity find&#40;long id&#41; throws DataAccessException &#123;
    		List results = getLocalTemplate&#40;&#41;.find&#40;
    				"from " + getPersistentClass&#40;&#41;.getName&#40;&#41; + " where id=" + id&#41;;
    		if &#40;results.size&#40;&#41; > 0&#41; &#123;
    			return &#40;&#40;Entity&#41; results.get&#40;0&#41;&#41;;
    		&#125; else &#123;
    			throw new IllegalArgumentException&#40;"No "
    					+ getPersistentClass&#40;&#41;.getName&#40;&#41; + " found with id&#58; " + id&#41;;
    		&#125;
    	&#125;
    
    	public void store&#40;Entity entity&#41; throws DataAccessException &#123;
    		if &#40;entity.getId&#40;&#41; == 0&#41; &#123;
    			getLocalTemplate&#40;&#41;.save&#40;entity&#41;;
    		&#125; else &#123;
    			getLocalTemplate&#40;&#41;.update&#40;entity&#41;;
    		&#125;
    	&#125;
    
    	public void store&#40;Collection collection&#41; throws DataAccessException &#123;
    		for &#40;Iterator iter = collection.iterator&#40;&#41;; iter.hasNext&#40;&#41;;&#41; &#123;
    			Entity element = &#40;Entity&#41; iter.next&#40;&#41;;
    			store&#40;element&#41;;
    		&#125;
    	&#125;
    
    	public void remove&#40;long id&#41; &#123;
    	    HibernateTemplate ht = this.getLocalTemplate&#40;&#41;;
    		Object o = ht.load&#40;getPersistentClass&#40;&#41;, new Long&#40;id&#41;&#41;;
    		ht.delete&#40;o&#41;;
    	&#125;
    
    	public List findLimited&#40;int numberToFind, String orderProp,
    			String orderByType&#41; &#123;
    		Query query;
    		try &#123;
    			query = this.getLocalTemplate&#40;&#41;.createQuery&#40;
    					this.getLocalSession&#40;&#41;,
    					"from " + this.getPersistentClass&#40;&#41;.getName&#40;&#41;
    							+ " order by " + orderProp + " " + orderByType&#41;;
    			query.setMaxResults&#40;numberToFind&#41;;
    			return &#40;query.list&#40;&#41;&#41;;
    
    		&#125; catch &#40;DataAccessResourceFailureException e&#41; &#123;
    			e.printStackTrace&#40;&#41;;
    		&#125; catch &#40;HibernateException e&#41; &#123;
    			e.printStackTrace&#40;&#41;;
    		&#125; catch &#40;IllegalStateException e&#41; &#123;
    			e.printStackTrace&#40;&#41;;
    		&#125;
    		return &#40;null&#41;;
    	&#125;
    
    	protected Criteria createCriteria&#40;&#41; throws HibernateException &#123;
    
    		return &#40;this.getLocalTemplate&#40;&#41;.createCriteria&#40;this.getLocalSession&#40;&#41;,
    				this.getPersistentClass&#40;&#41;&#41;&#41;;
    
    	&#125;
    
    	private Session getLocalSession&#40;&#41; &#123;
    		return &#40;SessionFactoryUtils.getSession&#40;this.getSessionFactory&#40;&#41;, true&#41;&#41;;
    	&#125;
    
    	private HibernateTemplate getLocalTemplate&#40;&#41; &#123;
    		return &#40;new HibernateTemplate&#40;this.getSessionFactory&#40;&#41;&#41;&#41;;
    	&#125;
    Here's my client code (a struts action):

    Code:
    public class AddLinkedArticlePlayerAction extends AdminAction &#123;
    
        /*
         * &#40;non-Javadoc&#41;
         * 
         * @see net.brewerfan.gui.admin.action.AdminAction#adminPerform&#40;org.apache.struts.action.ActionMapping,
         *      org.apache.struts.action.ActionForm,
         *      javax.servlet.http.HttpServletRequest,
         *      javax.servlet.http.HttpServletResponse,
         *      net.brewerfan.bizmodel.common.User&#41;
         */
        public ActionForward adminPerform&#40;ActionMapping mapping, ActionForm form,
                HttpServletRequest request, HttpServletResponse response, User user&#41;
                throws ApplicationException &#123;
    
            System.out.println&#40;"Starting transaction!"&#41;;
            
            AddLinkedArticlePlayerForm playerForm = &#40;AddLinkedArticlePlayerForm&#41; form;
    
            long playerId = Long.parseLong&#40;playerForm.getPlayerId&#40;&#41;&#41;;
    
            ArticleService service = &#40;ArticleService&#41; BrewerfanConstants.APPLICATION_CONTEXT
                    .getBean&#40;"articleService"&#41;;
            Player player;
            try &#123;
                player = service.findPlayer&#40;playerId&#41;;
            &#125; catch &#40;IllegalArgumentException e&#41; &#123;
                ActionErrors ae = new ActionErrors&#40;&#41;;
                ae.add&#40;"playerId",
                        new ActionError&#40;"error.common.playerId.notfound"&#41;&#41;;
                this.saveErrors&#40;request, ae&#41;;
                return &#40;new ActionForward&#40;mapping.getInput&#40;&#41;&#41;&#41;;
            &#125;
    
            LinkedArticle article = service.findLinkedAritcle&#40;playerForm
                    .getLinkedArticleId&#40;&#41;&#41;;
            Set players = article.getPlayers&#40;&#41;;
            if &#40;players == null&#41; &#123;
                players = new HashSet&#40;&#41;;
            &#125;
            players.add&#40;player&#41;;
            article.setPlayers&#40;players&#41;;
            service.store&#40;article&#41;;
    
            request.getSession&#40;&#41;.setAttribute&#40;"linkedArticleId",
                    Long.toString&#40;playerForm.getLinkedArticleId&#40;&#41;&#41;&#41;;
            
            System.out.println&#40;"Ending transaction!"&#41;;
    
            return this.getRedirectSuccess&#40;mapping&#41;;
        &#125;
    I'm getting "Initiating transaction commit" written out three times in stdout, so i'm assuming there is one transaction being started and stopped
    for each call to the service (which delegeates to the dao). I've been trying to figure this out on my own for a month now... any help for this
    novice would be greatly appreciated!

  2. #2
    Join Date
    Aug 2004
    Location
    Vrhnika, Slovenia
    Posts
    133

    Default

    Ofcourse you are getting new start/stop on each call of service, how should transaction know that you are not yet finished with it, that you have another DAO call ... ?

    You need to start transaction before Struts Action execution and commit/rollback after finish.

    Look at OpenSessionInViewInterceptor/Filter. Or write your own Action implementation that does similar things.

  3. #3
    Join Date
    Dec 2004
    Posts
    3

    Default

    Much obliged!

  4. #4
    Join Date
    Aug 2004
    Location
    Southampton, UK
    Posts
    826

    Default

    The methods of the object that you proxy demarcate the transaction boundaries. When building an application with Spring I tend to map each transaction to a particular method in the service tier then call all the methods that i need to be part of that transaction within the control flow of that method.

    Rob

  5. #5
    Join Date
    Dec 2004
    Posts
    3

    Default

    Quote Originally Posted by robh
    The methods of the object that you proxy demarcate the transaction boundaries. When building an application with Spring I tend to map each transaction to a particular method in the service tier then call all the methods that i need to be part of that transaction within the control flow of that method.

    Rob
    So there's no possible way that I can span a transaction over multiple calls to a proxy, even if I start the transaction externally (within the struts action)?

Similar Threads

  1. Replies: 5
    Last Post: Aug 25th, 2005, 05:37 PM
  2. Replies: 14
    Last Post: Feb 21st, 2005, 05:41 PM
  3. Replies: 3
    Last Post: Nov 19th, 2004, 07:16 PM
  4. Replies: 5
    Last Post: Aug 27th, 2004, 07:13 PM
  5. Replies: 7
    Last Post: Aug 21st, 2004, 03:42 AM

Posting Permissions

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