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

  • Hibernate cache with transactions

    As I understand it, Hibernate ensures that two copies of the same data loaded in the same session resolve to the same object instance.

    So the code below should work:
    testbed:
    Code:
      protected void setUp () throws Exception
        {
        :
        
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext (xmlLocs) ;
        
        zoneManager = (ZoneManager) ac.getBean ("zoneManager") ;
        hibernateTemplate = (HibernateTemplate) ac.getBean ("hibernateTemplate") ;
        }
    
      protected void tearDown ()
        {
        }
    
    public void testEquals () throws Exception
        {
        int c = zoneManager.count () ;
        assertEquals (c, 0) ;
        
        Zone zone1 = TestUtils.makeZone (1) ;
        zoneManager.add (zone1) ;
        Zone zoneOut1 = zoneManager.get (1) ;
        
        assertSame (zone1, zoneOut1) ;
    
    
        // Destroy 1st & 2nd level cache
        hibernateTemplate.flush () ;
        hibernateTemplate.clear () ;
    
    
        zoneOut1 = zoneManager.get (1) ;
        assertNotSame (zone1, zoneOut1) ;
        }
    zoneManagerDoa
    Code:
    @Transactional
    public class ZoneManagerDaoHibernate implements ZoneManagerDao
      {
      
      private HibernateTemplate hibernateTemplate ;
      
      public ZoneManagerDaoHibernate()
        {
        //
        }
      
      public void setHibernateTemplate (HibernateTemplate hibernateTemplate)
        {
        this.hibernateTemplate = hibernateTemplate ;
        }
      
      public Zone get (int id)
        {
        Object values[] = new Object[1] ;
        values[0] = new Integer (id) ;
        @SuppressWarnings("unchecked")
        List<Zone> l = hibernateTemplate.find ("from Zone z where z.id=?", values) ;
        if (l.size () == 0)
          return null ;
        Zone z = l.get (0) ;
        z.getClips ().size () ;
        return z ;
        }
       
      public int count ()
        {
        @SuppressWarnings("unchecked")
        List<Zone> l = hibernateTemplate.find ("from Zone z") ;
        return l.size() ;
        }
      
      public int add (Zone z)
        {
        Integer i = (Integer) hibernateTemplate.save (z) ;
        return Integer.valueOf (i) ;
        }
      
      }
    context
    Code:
    	<bean id="hypersonicDatasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    		<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
    		<property name="url" value="jdbc:hsqldb:mem:dbname"/>
    		<property name="username" value="sa"/>
    		<property name="password" value=""/>
    	</bean>
    	
    	<bean id="dataSource" class="com.xxx.sitemanager.testdb.TestDataSourceFactory">
    		<property name="datasource" ref="hypersonicDatasource"/>
    	</bean>
    
    	<tx:annotation-driven transaction-manager="transactionManager"/>
    
    	<bean id="sessionFactory"
    		class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    		<property name="dataSource" ref="dataSource" />
    		<property name="mappingResources">
    			<list>
    				<value>my hbm.xml</value>
    				<value>my hbm.xml</value>
    			</list>
    		</property>
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
    				<prop key="hibernate.show_sql">true</prop>
    				<prop key="hibernate.format_sql">true</prop>
                	<prop key="hibernate.hbm2ddl.auto">create-drop</prop>
    			</props>
    		</property>
    	</bean>
    	
    	<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
    		<property name="sessionFactory" ref="sessionFactory"/>
    	</bean>
    	
    	<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    		<property name="sessionFactory" ref="sessionFactory"/>
    	</bean>
    
    
    	<bean id="zoneManagerDaoHibernate" class="com.xxx.SiteManager.adaptor.isa.zone.ZoneManagerDaoHibernate">
    		<property name="hibernateTemplate" ref="hibernateTemplate"/>
    	</bean>
    
    	<bean id="zoneManager" class="com.xxx.SiteManager.adaptor.isa.zone.ZoneManager">
    		<property name="zoneManagerDao" ref="zoneManagerDaoHibernate"/>
    	</bean>
    This is running under a JUnit test which is failing on "assertSame (zone1, zoneOut1) ;" that is the object returned from the get is not the same object as was placed in the zoneManager.

    If I change setup() to:
    Code:
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext (xmlLocs) ;
        
        zoneManager = (ZoneManager) ac.getBean ("zoneManager") ;
        hibernateTemplate = (HibernateTemplate) ac.getBean ("hibernateTemplate") ;
    
        session = SessionFactoryUtils.getSession (hibernateTemplate .getSessionFactory (), true) ;
        TransactionSynchronizationManager.bindResource (hibernateTemplate.getSessionFactory (), new SessionHolder (
            session)) ;
        }
    and the tearDown() to:
    Code:
    protected void tearDown ()
        {
        TransactionSynchronizationManager.unbindResource (hibernateTemplate .getSessionFactory ()) ;
        SessionFactoryUtils.releaseSession (session, hibernateTemplate.getSessionFactory ()) ;
        }
    Then it all works.

    My question is:
    1. The (at)Transactional annotations in the zoneManager are picked up so I'm not getting LazyInitialisation when hydrating other objects, so why is it that I need this extra code to explicitly bind a transaction manager when my beans are already using a transaction manager with the hibernate sessionFactory?

    2. All the examples I have seen do not use the TransactionSynchronizationManager so is there a way of doing this in the xml file? Is this the accepted way to run these tests?

    I have been struggling with this and LazyIEs for over a week, so any help or advice will be greatly appreciated.

  • #2
    Because your test needs a transaction at the JUnit level and there is none unless you create it yourself. That's why there are Spring helper classes that support transactional JUnit test methods.

    Comment


    • #3
      Thank you. It seems a bit odd that this way of doing this is not mentioned in the reference documentation. Is there some other way that everyone else uses?

      Please could you outline some of the useful helper classes that tackle this problem?

      Comment


      • #4
        Transaction management in JUnit tests.

        Comment

        Working...
        X