Page 1 of 2 12 LastLast
Results 1 to 10 of 11

Thread: Call to getHibernateTemplate().saveOrUpdate(Object) does not persist the data

  1. #1

    Default Call to getHibernateTemplate().saveOrUpdate(Object) does not persist the data

    Code:
    public void saveChangeCase(ChangeCase changeCase)
    {        
         HibernateTemplate template = getHibernateTemplate();
          
         template.saveOrUpdate(changeCase);          
    
         System.out.println(changeCase.getChangecaseid());
    }
    The output is 63, which is what is expected. However, when I hit the database, the record is not there.

    What gives?

  2. #2

    Default Got it to work w/ this implementation...

    Code:
    public void saveChangeCase(final ChangeCase changeCase)
        {        
            
            
            HibernateTemplate template = getHibernateTemplate();
           
            template.execute(
                    new HibernateCallback()
                    {
                        public Object doInHibernate(Session session) throws HibernateException
                        {
                            Transaction tx = session.beginTransaction();
                            
                            tx.begin();
                            session.save(changeCase);
                            tx.commit();
                            session.close();
                            return null;
                        }
                    }
                    );        
        }
    Is that the best approach with Hibernate 3.1?

  3. #3
    Join Date
    Dec 2005
    Location
    U-241
    Posts
    237

    Default

    Houston, we've got a problem!

    Houston? Or should I say - Thomas Risberg?

    OK. As you know, org.springframework.orm.hibernate3.LocalSessionFac toryBean has a method setConfigLocation(Resource configLocation)
    According to docs the purpose of the method -
    'Set the location of the Hibernate XML config file, for example as classpath resource "classpath:hibernate.cfg.xml"'.
    When I inject my hibernate.cfg.xml with all configuration data (data source, mapping files and all)

    <bean id="sessionFactory" class="&LocalSessionFactoryBean;">
    <property name="configLocation" value="hibernate.cfg.xml" />
    </bean>

    Spring accepts this, runs, and displays that data are generated, processed and sent to database. Yet nothing is updated in the database.
    To make the data stick we have to revert to Hibernate callbacks. \
    Is it really the way it is supposed to be?
    Is there something fishy in terms of supporting configuration params from hibernate.cfg.xml? Or we have something missing?

    Cheers,
    Arno
    Last edited by Arno Werr; Jan 5th, 2006 at 08:34 AM.
    Spring, it's a wonderful thing...

  4. #4
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    You should use a transaction manager to handle transactions for you - placeing them inside the hb callback is not a good idea since you'll have to handle exceptions by yourself (which you don't at this point).
    Make sure you flush the connection - this way you'll tell HB to persist the changes.
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  5. #5
    Join Date
    Dec 2005
    Location
    U-241
    Posts
    237

    Default

    Costin, I agree with you 100%. Hibernate callbacks, native Hibernate exceptions and programmatic transaction handling is not the way Spring should work. At least as much as I see Spring philosophy. Yet here is the problem. There are two ways of configuring Spring to work with Hibernate.
    The first approach - traditional. We have applicationContext.xml, jdbc.properties and hibernate.properties.

    applicationContext.xml looks like this. (I am using XML general entities. Consider them as placeholders)
    Code:
    <beans>
       <bean class="&PropertyPlaceholderConfigurer;">
            <property name="locations">
                <list>
                    <value>classpath:jdbc.properties</value>
                    <value>classpath:hibernate.properties</value>
                </list>
            </property>
        </bean>
        <bean id="dataSource" class="&BasicDataSource;"
            destroy-method="close">
            <property name="driverClassName"
                value="${jdbc.driverClassName}" />
            <property name="url" value="${jdbc.url}" />
            <property name="username" value="${jdbc.username}" />
            <property name="password" value="${jdbc.password}" />
        </bean>
        <bean id="sessionFactory" class="&LocalSessionFactoryBean;">
            <property name="dataSource" ref="dataSource" />
            <property name="mappingResources">
                <list>
                    <value>foo.hbm.xml</value>
                    <value>bar.hbm.xml</value>
                </list>
            </property>
            <property name="hibernateProperties">
                <props>
                    <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                    <prop key="hibernate.max_fetch_depth">${hibernate.max_fetch_depth}</prop>
                </props>
            </property>
        </bean>
       
        <bean id="abstractSessionFactoryHost" abstract="true">
            <property name="sessionFactory" ref="sessionFactory" />
        </bean>
        <bean id="transactionManager" class="&HibernateTransactionManager;"
            parent="abstractSessionFactoryHost" />
        <bean id="fooDao" class="&fooDaoImpl;"
            parent="abstractSessionFactoryHost" />
        <bean id="barDao" class="&barDaoImpl;"
            parent="abstractSessionFactoryHost" />
    </beans>
    So data source values are located in jdbc.properties and Hibernate values in hibernate.properties (though you can mix them in a single file).
    When I run this traditional configuration data stick in database. All is fine.

    There is another configuration which I call Hibernate specific. It looks like this
    Code:
    <beans>
        <bean id="sessionFactory" class="&LocalSessionFactoryBean;">
            <property name="configLocation" value="classpath:hibernate.cfg.xml" />
        </bean>
       
        <bean id="abstractSessionFactoryHost" abstract="true">
            <property name="sessionFactory" ref="sessionFactory" />
        </bean>
        <bean id="transactionManager" class="&HibernateTransactionManager;"
            parent="abstractSessionFactoryHost" />
        <bean id="fooDao" class="&fooDaoImpl;"
            parent="abstractSessionFactoryHost" />
        <bean id="barDao" class="&barDaoImpl;"
            parent="abstractSessionFactoryHost" />
    </beans>
    All values from jdbc.properties, hibernate properties, and *.hbm.xml files are now in hibernate.cfg.xml. In all other respects configurations are identical.
    As you see, applicationContext.xml is more readable (less clutter) and allows me to reuse existing investment in hibernate.cfg.xml.
    Like once Bill wrote to me 'heck, I already have gone through the pain of setting up all the .hbm.xml files. might as well use them right?'
    So semantically both configurations should be identical. The difference is in sintax and reusability of existing investments.
    Yet there is a huge difference in runtime. When I run the second (i.e. configuration based on hibernate.cfg.xml) Spring does not persist data.
    It runs, displays output, but nothing sticks in database. I know from correspondence with Bill that he was trying configuration based on hibernate.cfg.xml as well and facing persistence problem resorted to direct Hibernate callbacks. But without those callbacks Spring does not stick the data. So the question is - Why data is not persistent when we are using Spring configuration based on hibernate.cfg.xml?

    Cheers,
    Arno
    Last edited by Arno Werr; Jan 5th, 2006 at 09:16 AM.
    Spring, it's a wonderful thing...

  6. #6
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    I get your point Arno. I can't answer the question but it would be great if you could create a very simple test case to ilustrate the bug and post in on JIRA. There might be a subtle bug where hibernate being initialized through the XML has other settings then set up through Spring specific support. It might have something to do with the changes in HB 3.1 releated to connection settings.
    Try running your configuration on HB 3.0.5 and see if you still have the problem - the same code should behave the same for the same configuration (just make sure they are the same).
    Turn on logging and spot any differences in the HB SF configuration - a quick solution would be in each case (Spring and HB specific) to get a hold of the configuration object and somehow make it print all the settings - actually you can inspect the object settings yourself through JMX (it's quite easy to run expose this).
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  7. #7
    Join Date
    Dec 2005
    Location
    U-241
    Posts
    237

    Default

    Hi Costin,

    OK.
    I've got a test case up and running.
    Java code, *.hbm.xml files are identical. In terms of configuration the only difference in connection providers.
    In 'Spring only' configuration I am using org.springframework.jdbc.datasource.DriverManagerD ataSource
    In Spring with HB.cfg.xml - HB native org.hibernate.connection.DriverManagerConnectionPr ovider. HB 3.0.5 file is from Spring 1.2.4 distribution.
    The same buggy behavior. When using hibernate.cfg.xml configuration - data is not persisted.

    Question - how to post the test case to JIRA?

    Next question relates to your idea 'a quick solution would be in each case (Spring and HB specific) to get a hold of the configuration object and somehow make it print all the settings - actually you can inspect the object settings yourself through JMX (it's quite easy to run expose this).'
    Well, I am not very privy to JMX ('JM' who? , so how the heck should I do it? OK, Ok, I am using Tomcat/JBoss Admin console. But that's about it.

    Cheers,
    Arno
    Spring, it's a wonderful thing...

  8. #8
    Join Date
    Dec 2005
    Location
    U-241
    Posts
    237

    Default

    Yeah, I guess I found it...

    What I was missing in my hibernate.conf.xml was a single line

    Code:
    <property name="connection.autocommit">true</property>
    With autocommit true it is running like a charm. Well, but I do not have to declare autocommit=true in my Spring only configuration...

    Oh Mommy, oh mommy, mommy Blue
    Spring, it's a wonderful thing...

  9. #9
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    In 'Spring only' configuration I am using org.springframework.jdbc.datasource.DriverManagerD ataSource
    In Spring with HB.cfg.xml - HB native org.hibernate.connection.DriverManagerConnectionPr ovider. HB 3.0.5 file is from Spring 1.2.4 distribution.
    Both HB and Spring advice against using these datasources because they do not have any pooling or any features that you would need in a production environment - they and also I suggest to use an approapriate datasource like c3p0 or Commons dbcp.
    You'll have no problem no matter if connection.autocommit is set to true or false.
    Note that this parameter should be turned to false when using transactions otherwise the information will always hit the database even when the transaction is not commited yet.
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  10. #10
    Join Date
    Dec 2005
    Location
    U-241
    Posts
    237

    Default

    Quote Originally Posted by costin
    Both HB and Spring advice against using these datasources because they do not have any pooling or any features that you would need in a production environment - they and also I suggest to use an approapriate datasource like c3p0 or Commons dbcp.
    True. I deliberately opted for driver managers to remove from tests all pooling management relating issues. In production there should be pools indeed. Here's a question though. If I am using Spring only configuration then Spring provides life-cycles services to the pool including destroy-method callbacks:
    Code:
    <bean id="dataSource" class="&BasicDataSource;"  destroy-method="close"/>
    When I am using Spring+HB configuration then what? No life-cycle services? All initialization and destroy methods should be configured in hibernate.cfg.xml?
    Quote Originally Posted by costin
    You'll have no problem no matter if connection.autocommit is set to true or false.
    Note that this parameter should be turned to false when using transactions otherwise the information will always hit the database even when the transaction is not commited yet.
    Actually I have a problem. In Spring+HB config with autocommit=false (which is definitely is the most appropriate option) I have to wrap my target into transactional proxy.Otherwise nothing sticks with database (actually, it's the way it's supposed to be). So my configuration looks like this.
    Code:
    <beans>
    	<bean id="sessionFactory" class="&LocalSessionFactoryBean;">
    		<property name="configLocation"
    			value="classpath:hibernate.cfg.xml" />
    	</bean>
    	<bean id="abstractSessionFactoryHost" abstract="true">
    		<property name="sessionFactory" ref="sessionFactory" />
    	</bean>
    	<bean id="eventDao" class="&TransactionProxyFactoryBean;">
    		<property name="transactionManager">
    			<bean class="&HibernateTransactionManager;"
    				parent="abstractSessionFactoryHost" />
    		</property>
    		<property name="target">
    			<bean class="&EventDaoImpl;"
    				parent="abstractSessionFactoryHost" />
    		</property>
    		<property name="transactionAttributes">
    			<props>
    				<prop key="get*">PROPAGATION_REQUIRED</prop>
    				<prop key="save*">PROPAGATION_REQUIRED</prop>
    			</props>
    		</property>
    	</bean>
    </beans>
    Strangely, in Spring only configuration without explicit setting of autocommit policy (I guess it's false by default?) and without proxying the target Spring persists the data...

    Here's my Spring only config with pool and without tranxactional proxy
    Code:
    <beans>
    	<bean class="&PropertyPlaceholderConfigurer;">
    		<property name="locations">
    			<list>
    				<value>classpath:jdbc.properties</value>
    				<value>classpath:hibernate.properties</value>
    			</list>
    		</property>
    	</bean>
    
           <bean id="dataSource" class="&BasicDataSource;"
    		        destroy-method="close">		
                     <property name="driverClassName" value="${jdbc.driverClassName}" />
    		<property name="url" value="${jdbc.url}" />
    		<property name="username" value="${jdbc.username}" />
    		<property name="password" value="${jdbc.password}" />
    	</bean>
    	
            <bean id="sessionFactory" class="&LocalSessionFactoryBean;">
    		<property name="dataSource" ref="dataSource" />
    		<property name="mappingResources">
    			<list>
    	  		  <value>Attendee.hbm.xml</value>
    				<value>Event.hbm.xml</value>
    				<value>Location.hbm.xml</value>
    				<value>Speaker.hbm.xml</value>
    			</list>
    		</property>
    
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">
    					${hibernate.dialect}
    				</prop>
    				<prop key="hibernate.max_fetch_depth">
    					${hibernate.max_fetch_depth}
    				</prop>
    			</props>
    		</property>
    	</bean>
    
    	<bean id="abstractSessionFactoryHost" abstract="true">
    		<property name="sessionFactory" ref="sessionFactory" />
    	</bean>
    
    	<bean id="transactionManager" class="&HibernateTransactionManager;"
    		parent="abstractSessionFactoryHost" />
    	
            <bean id="eventDao" class="&EventDaoImpl;"
    	     parent="abstractSessionFactoryHost" />
    </beans>
    Hm...
    Spring, it's a wonderful thing...

Posting Permissions

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