Announcement Announcement Module
Collapse
No announcement yet.
HibernateDaoSupport: Transactions Best Practices? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • HibernateDaoSupport: Transactions Best Practices?

    I have several questions regarding extending org.springframework.orm.hibernate.support.Hibernat eDaoSupport. Forgive my ignorance, as I have read the documentation, and attempted to follow the code, but I need an expert's clarification.

    All my DAOs extend HibernateDaoSupport. The API states the following:

    The central method is "execute", supporting Hibernate code implementing the HibernateCallback interface. It provides Hibernate Session handling such that neither the HibernateCallback implementation nor the calling code needs to explicitly care about retrieving/closing Hibernate Sessions, or handling Session lifecycle exceptions.
    Given this, what is the best manner to manage a single transaction amid several DAOs? Please consider the following code:

    Code:
    ThreadDAO dao = (ThreadDAO) DAOFactory.getInstance(ThreadDAO.class);
    dao.save(pForm.getNewThread());
    		
    Post post = pForm.getNewPost();
    post.setTimePosted(new Timestamp(System.currentTimeMillis()));
    post.setMostRecentEdit(post.getTimePosted());
    post.setThreadID(pForm.getNewThread().getId());
    pForm.setNewPost(post);
    		
    PostDAO pDao = (PostDAO) DAOFactory.getInstance(PostDAO.class);
    pDao.save(pForm.getNewPost());
    (Note: The DAOFactory does pool the same DAO for all requests of that class of object, but I have been assured before it is thread-safe. Please correct this if wrong.)

    First, does the above code use the same Session? It is stored in a ThreadLocal variable? If so, when is it closed?

    In the past, I've done something like this, passing a Session or Transaction object around.

    Code:
    Session session = someFactory.getSession() ;
    Transaction tx = session.beginTransaction() ;
    ThreadDAO dao = (ThreadDAO) DAOFactory.getInstance(ThreadDAO.class);
    dao.save(session, pForm.getNewThread());
    		
       ... continue through above code
    
    tx.commit() ;
    session.close() ;
    However, I would love to not "explicitly care" about the underlying session or transaction, as the Spring HibernateDaoSupport suggests.

    Please offer any suggestions or comments. I look forward to your help.

    Lukas

  • #2
    I wanted to include my settings for more information.

    Code:
    <beans>	
    	<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
    		<property name="mappingResources">
    			<list>
    				<!-- My HBM.XML files here -->
    			</list>
    		</property>
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</prop>
    				<prop key="hibernate.show_sql">yes</prop>
    				<!-- Configure Proxool connection pool from this configuration file. -->
    				<prop key="hibernate.proxool.xml">proxool.xml</prop>
    				<prop key="hibernate.proxool.pool_alias">spring</prop>
    			</props>
    		</property>
    	</bean>
    	
    	<!-- The DAOFactory is responsible for creating and managing DAO instances. -->
    	<bean id="daoFactory" class="p2p.dao.DAOFactory">
    		<property name="sessionFactory">
    			<!-- The following bean name should correspond to the LocalSessionFactoryBean id above. -->
    			<ref bean="sessionFactory" />
    		</property>
    	</bean>
    </beans>
    My proxool configuration only has JDBC connection info, with 2 min/10max connections.

    Comment


    • #3
      Lukas,

      The way that you are code is presented below goes against how the Spring IoC container works. Code like this:

      Code:
      ThreadDAO dao = &#40;ThreadDAO&#41; DAOFactory.getInstance&#40;ThreadDAO.class&#41;;
      goes outside the Spring IoC framework and leaves you with the old ServiceLocator pattern. There are several problems with this line alone that can get you into trouble. First, ThreadDAO does not appear as a managed bean by the Spring container (i.e. it does not appear in the applicationContext.xml file in your example). Second, since the object is not recoginzed as bean in the container you are experiencing the DAO issues and Session/TX handling that you are expecting. Third, you should make better use of interfaces that you can implement for classes like ThreadDAO. I would suggest a class structure for this particular DAO to have an interface called IThreadDAO and implementation classes like IThreadHibernateDAO, IThreadIBatisDAO, IThreadJDBCDAO, etc. The Spring configuration specifies the implementation that your required at runtime. By using the Spring framework as intended you will get the benefit of being able to switch implemenations without chaning your code by updating the config file.

      Once you have arranged your files in the Spring framework you will be able to make use of the Spring features such as DAO handling. You can then allow Spring to manage your transactions through the config file as an AOP interceptor (and underlying Session through the DAO templates).

      I would suggest introducing a service locator layer into your architecture that Spring manages. Then wire your DAO objects into your service locator objects with setter dependency injection. Furthermore, your sessionFactory should be injected into your DAO object. Then the basic flow is to get an instance of the service object from the Spring context (not getInstance like a singleton). From there you can call getWhateverDAO and return it as an interface. That plus the correct Spring context configuration for the transaction AOP interceptor will get you the results you wanted.

      Hope this helps.

      Mark

      Comment


      • #4
        I would suggest a class structure for this particular DAO to have an interface called IThreadDAO and implementation classes like IThreadHibernateDAO, IThreadIBatisDAO, IThreadJDBCDAO, etc. The Spring configuration specifies the implementation that your required at runtime. By using the Spring framework as intended you will get the benefit of being able to switch implemenations without chaning your code by updating the config file.
        Understood.

        So let's say IThreadDAO has a method like this:

        Code:
        public void saveNewPost&#40;Post pPost&#41; ;
        I'm having a hard time determining

        a) What object ThreadDaoHibernateImpl extends, and
        b) how to define that within the applicationConfiguration.

        My major problem areas have question marks around them. I just don't know what should reference what.

        Code:
        <?xml version="1.0" encoding="UTF-8"?>
        <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http&#58;//www.springframework.org/dtd/spring-beans.dtd">
        <beans>
        	<!-- Factory tasked with pooling the sessions for our persistence layer. -->
        	<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
        		<property name="mappingResources">
        			<list>
        				<!-- List of HBM files to be loaded and supported by persistence layer. -->
        
        			</list>
        		</property>
        		<property name="hibernateProperties">
        			<props>
        				<prop key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</prop>
        				<prop key="hibernate.show_sql">yes</prop>
        				<!-- Configure Proxool connection pool from this configuration file. -->
        				<prop key="hibernate.proxool.xml">proxool.xml</prop>
        				<prop key="hibernate.proxool.pool_alias">spring</prop>
        			</props>
        		</property>
        	</bean>
        	
        	<bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" />
        
        	<!-- Hibernate Interceptor -->
        	<bean id="hibernateInterceptor" class="org.springframework.orm.hibernate.HibernateInterceptor">
        		<property name="sessionFactory">
        			<ref local="sessionFactory"/>
        		</property>
        	</bean> 
        	
        	<bean id="transactionInterceptor" 
        		class="org.springframework.transaction.interceptor.TransactionInterceptor">
        		<!-- Inject the transaction manager defined above. -->
        		<property name="transactionManager">
        			<ref local="jtaTransactionManager"/>
        		</property>
        		<property name="transactionAttributeSource">
        			<value>
        	p2p.common.forum.???ThreadDAOImpl???.saveNewPost=PROPAGATION_REQUIRED
        			</value>
        		</property>
        	</bean>
        	
        	<!-- Forum logic -->
        	<bean id="ThreadTarget" class="p2p.common.forum.???WhatClassGoesHere???"
        		<property name="sessionFactory">
        			<ref local="sessionFactory"/>
        		</property>
        	</bean>
        	<bean id="ThreadDAO" class="org.springframework.aop.framework.ProxyFactoryBean">
        		<property name="proxyInterfaces">
        			<value>p2p.common.forum.???WhatClassGoesHere???</value>
        		</property>
        		<property name="interceptorNames">
        			<list>
        				<value>transactionInterceptor</value>
        				<value>hibernateInterceptor</value>
        				<value>ThreadTarget</value>
        			</list>
        		</property>
        	</bean>
        </beans>
        There just isn't a clear-cut example anywhere (that I can find) of what I want to do. I've looked at the docs, the Wiki, and even purchased the Spring book online, but the chapter I need isn't released yet.... *sigh*

        Lukas

        Comment


        • #5
          Note: HibernateDaoSupport Desired

          I would like for my DAOs (aka business objects) to extend HibernateDaoSupport.

          What factory returns my transactionally safe HibernateDaoSupport classes, and how do I access it?

          This is what I want:

          Code:
          	private String saveNewThread&#40;
          		ActionMapping pActionMapping,
          		ThreadForm pForm,
          		HttpServletRequest pRequest&#41; throws HibernateException
          	&#123;
          		// Create the new thread
          		Threads thread = pForm.getNewThread&#40;&#41;;
          		thread.setUserLoginID&#40;UserAccess.get&#40;&#41;.getId&#40;&#41;&#41;;
          		thread.setForumID&#40;pForm.getForumID&#40;&#41;&#41;;
          		
          		mLogger.debug&#40;"saving thread"&#41; ;
          		// And save it
          		// Where do I get a link to springApplicationContext?!
          ThreadDAO threadDAO = &#40;ThreadDAO&#41; springApplicationContext.getBean&#40;"ThreadDAO"&#41;;
          		//ThreadDAO dao = &#40;ThreadDAO&#41; DAOFactory.getInstance&#40;ThreadDAO.class&#41;;
          		dao.save&#40;thread&#41;;
          		pForm.setNewThread&#40;thread&#41;;
          		
          		Post post = pForm.getNewPost&#40;&#41;;
          		post.setTimePosted&#40;new Timestamp&#40;System.currentTimeMillis&#40;&#41;&#41;&#41;;
          		post.setMostRecentEdit&#40;post.getTimePosted&#40;&#41;&#41;;
          		post.setThreadID&#40;thread.getId&#40;&#41;&#41;;
          		
          		mLogger.debug&#40;"saving post"&#41; ;
          		PostDAO pDao = &#40;PostDAO&#41; springApplicationContext.getBean&#40;"PostDAO"&#41;;
          		pDao.save&#40;post&#41;;
          		pForm.setNewPost&#40;post&#41;;
          	
          		return "success";
          	&#125;

          Comment

          Working...
          X