Announcement Announcement Module
Collapse
No announcement yet.
howto commit after saveUpdate() Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • howto commit after saveUpdate()

    i am using hibernate template and am writing data with saveOrUpdate() through hibernateTemplate.

    never the less when using filebased database nothing gets persisted (after query i get empty sets after another test run from a fresh app-startup).
    i am using:
    Code:
    <prop key="hibernate.connection.url">jdbc:hsqldb:file:testdb</prop>
    <prop key="hibernate.hbm2ddl.auto">update</prop>
    i thought that by using saveOrUpdate() hibernate template does a commit behind the scenes or do i need to set a transaction manager, which forces commits, explicitly?

    a <prop key="hibernate.connection.autocommit">true</prop> would not work either.

  • #2
    Normally the transaction boundaries are not defined on top of the dao calls. In most cases the transaction should be defined on some kind of service method:

    @Transactional
    EmployeeService.giveAllEmployeesChristmasPackage()

    In most cases you need to do multiple dao calls and you want to execute all these call as a single unit of work. So committing (or rolling back) normally is defined on these boundaries and not on the dao's.

    Comment


    • #3
      @Transaction does not work.

      to be more detailled: i am using a simple persistenceAccess wrapper, which is straight transactional. in know it does not fit all purposes but for my simple requirements (always commit instantly) it is fine. the hibernate version looks like following (all modify methods should be transactional by convention):

      Code:
      public class HibernateAccess implements IPersistenceAccess {
      
          public HibernateTemplate hibernateTemplate;
      
          /**
           * {@inheritDoc}
           */
          //straight commit
          public void delete(Object obj) {
              hibernateTemplate.delete(obj);
              hibernateTemplate.flush();
          }
      
          /**
           * {@inheritDoc}
           */
          public Set<?> find(String query) {
              Set<Object> queryResult = new HashSet<Object>();
              for (Object o : hibernateTemplate.find(query)) {
                  queryResult.add(o);
              }
              return queryResult;
          }
      
          /**
           * {@inheritDoc}
           */
          //straight commit
          public void saveOrUpdate(Object obj) {
              hibernateTemplate.saveOrUpdate(obj);
              hibernateTemplate.flush();
          }
      
          public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
              this.hibernateTemplate = hibernateTemplate;
          }
      
      }
      this hibernate wrapper is used inside service methods which need persisting functionality:

      Code:
      public class MyService implement IService{
          private IPersistenceAccess persistenceAccess;
      
          public void setPersistenceAccess(IPersistenceAccess pa){
             this.persistenceAccess=pa;
          }
          ...
          //some write actions
      
          public void writeData(Object dataObj){
             ...
             //persist dataObject instantly (transaction-start/end before/after saveOrUpdate() )
             persistenceAccess.saveOrUpdate(dataObj);
          }
          ...
      
      }

      Comment


      • #4
        Flush <> commit. Flush only generates sql statements. You don't need to commit those statements only if you run with autocommit=true.

        Comment


        • #5
          Forgot to mention why your code doesn't work - if there is no transaction each hibernatetemplate method invocation gets it's own session/connection. So the sesssion used for saving is not the session that you flush.

          Comment


          • #6
            so what do i need to do, that

            hibernateTemplate.saveOrUpdate(obj);

            gets commited?

            i tried both <prop key="hibernate.connection.autocommit"></prop> true and false, which does not work.

            Comment


            • #7
              a) create a transaction
              b) set hibernatetemplate.flushmode to always
              c) execute both session.saveOrUpdate and session.flush in one hibernatetemplate.execute callback

              Comment


              • #8
                i followed your a,b,c advices, but still no success:

                snippets of spring config:

                Code:
                <beans>
                ...
                	<bean id="hibernateTemplate"
                		class="org.springframework.orm.hibernate3.HibernateTemplate">
                		<property name="sessionFactory">
                			<ref bean="sessionFactory" />
                		</property>
                	</bean>
                
                	<bean id="transactionManager"
                		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
                		<property name="sessionFactory" ref="sessionFactory" />
                	</bean>
                
                	<bean id="transactionTemplate"
                		class="org.springframework.transaction.support.TransactionTemplate">
                		<property name="transactionManager">
                			<ref bean="transactionManager" />
                		</property>
                	</bean>
                
                	<bean id="persistenceHibernateAccess"
                		class="org.bla.persistence.hibernate.HibernateAccess">
                		<property name="hibernateTemplate">
                			<ref bean="hibernateTemplate" />
                		</property>
                	</bean>
                ...
                </beans>
                code doing transaction:
                Code:
                public void saveOrUpdate(final Object obj) {
                        hibernateTemplate.setFlushMode(HibernateTemplate.FLUSH_ALWAYS);
                        BeanFactory.getTransactionTemplate().execute(new TransactionCallback() {
                            public Object doInTransaction(TransactionStatus status) {
                                try {
                                    return hibernateTemplate.execute(new HibernateCallback(){
                                        @Override
                                        public Object doInHibernate(Session session) throws HibernateException, SQLException {
                                            session.saveOrUpdate(obj);
                                            session.flush();
                                            return null;
                                        }
                                    });                    
                                } catch (Exception e) {
                                    logger.error("Transaction saveOrUpdate() failed.");
                                    return null;
                                }                
                            }
                        });
                    }
                data still does not get persisted, why?

                Comment


                • #9
                  Actually, I meant "a or b or c" not "a and b and c".

                  I can't see how can the above setup fail to persist something.

                  Comment


                  • #10
                    Originally posted by dejanp View Post
                    Actually, I meant "a or b or c" not "a and b and c".
                    that was a good one :P. wondered already why things are getting messy and complicated with spring...

                    yes it's weird that it does not work. maybe there are problems with database settings (and resources and connection are not shut down properly or schema is dropped). to check this out, some more configurations:

                    Code:
                    <beans>
                    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
                     <property name="hibernateProperties">
                    	<props>
                    	 <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
                             <prop key="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</prop>
                             <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
                             <prop key="hibernate.connection.url">jdbc:hsqldb:file:testdb</prop>
                             <prop key="hibernate.connection.username">sa</prop>
                             <prop key="hibernate.connection.password"></prop>
                             <prop key="hibernate.show_sql">true</prop>
                    	 <prop key="hibernate.hbm2ddl.auto">update</prop>
                            </props>
                         </property>
                    
                    ...for other beans see previous post
                    </beans>

                    now, have a look at my test case (i know not a real one for it is not a fresh test). when running first time test succeeds, when running second time (with commenting out a.saveOrUpdate()) it fails:
                    Code:
                    public class DBTest extends TestCase {
                    
                        public void testEntriesPersist() throws Exception {        
                            HibernateAccess a=(HibernateAccess)BeanFactory.getPersistenceHibernateAccess();
                            a.saveOrUpdate(new Mandator("name"));
                            Set man=a.find("from Mandator");
                            assertFalse(man.isEmpty());
                        }
                    }
                    maybe the jdbc url string is wrong. but i thought that jdbc:hsqldb:file:testdb is a persistent source and does not get deleted. i had a look to the file system and following files are created:
                    testdb.properties
                    testdb.lck
                    testdb.log

                    what i wonder is, where to find the database file where data is persisted inside. this excludes testdb.{properties|log}. so it must be testdb.lck...? maybe file-database resource gets accidently deleted, so when executing test case no data can be read?

                    Comment


                    • #11
                      i got to my goal. i got a configuration where persisting works

                      first of all persisting did only work with option a), where code gets executed inside transaction-callback:
                      Code:
                      public void saveOrUpdate(final Object obj) {
                       BeanFactory.getTransactionTemplate().execute(new TransactionCallback(){
                         public Object doInTransaction(TransactionStatus status) {
                           hibernateTemplate.saveOrUpdate(obj);
                           return null;
                         }
                       });
                      }
                      further more there seem to be hsqldb issues. persisting was only successful when i used the hsqldb database server option with network stack (url pattern jdbc:hsqldb:hsql://localhost/xdb). using file based version without network stack (url pattern jdbc:hsqldb:file:testdb) failed, even when combined with transaction-callback pattern (see above).

                      besides: though the code does not get really readable (through anonymous classes), it is at least encapsulated in one single method. let's hope in future, closures will be included in java language....

                      Comment

                      Working...
                      X