Announcement Announcement Module
Collapse
No announcement yet.
Problem with rollback on exception Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Problem with rollback on exception

    Hi,

    I have spring application, accessing Postgres (8.x) database through Hibernate 3. In recent time i have noticed that DB changes in my service method are not rolled back when exception happens. My application is running on jboss 4.2.3, and using jndi XA datasource to connect to postgres.

    During debugging I have noticed that org.springframework.orm.hibernate3.SpringSessionSy nchronization.beforeCommit(boolean readOnly) is called. This method is flushing the session which is resulting in DataAccessException. At this point when I browse my database I see that entities created in service method (except one that is causing the problem) are already stored in database. Subsequently rollback method is called but it didn't change anything.

    My application is generated with andromda using hibernate3 cartridge. I have tried to update spring version to 2.5.6 and hibernate to 3.2.7.ga but didn't help.

    Does somebody has an idea why these changes are not rolled back? Thanx.

  • #2
    I would say wrongly configured transactions.

    Comment


    • #3
      I had:

      Code:
      <beans>
          <!-- ========================= DATASOURCE DEFINITION ========================= -->
      
          <!-- JNDI DataSource for J2EE environments -->
          <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
              <property name="jndiName"><value>java:/jdbc/MyAppDatasource</value></property>
          </bean>
      
          <!-- ====================== End of DATASOURCE DEFINITION ====================== -->
      
          <!-- ===================== TRANSACTION MANAGER DEFINITION ========================= -->
      
          <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                  <property name="dataSource"><ref bean="dataSource"/></property>
          </bean>
      
          <!-- ===================== TRANSACTION MANAGER DEFINITION ========================= -->
      
      </beans>
      and when i replaced transaction manager with HibernateTransactionManager it started working as expected:

      Code:
          <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
              <property name="jndiName"><value>java:/jdbc/myAppDatasource</value></property>
          </bean>
      
          <!-- ====================== End of DATASOURCE DEFINITION ====================== -->
      
          <!-- ===================== TRANSACTION MANAGER DEFINITION ========================= -->
      
          <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
                  <property name="dataSource"><ref bean="dataSource"/></property>
                  <property name="sessionFactory"><ref bean="sessionFactory"/></property>
          </bean>
      The rest of relevant configuration:
      Code:
          <!-- Hibernate SessionFactory -->
          <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
              <property name="dataSource"><ref bean="dataSource"/></property>
              <property name="mappingLocations"><ref bean="hibernateMappingLocations"/></property>
              <property name="hibernateProperties"><ref bean="hibernateProperties"/></property>
              <!-- applicationContext sessionFactory merge-point -->
          </bean>
      
          <!-- The Hibernate interceptor -->
          <bean id="hibernateInterceptor" class="org.springframework.orm.hibernate3.HibernateInterceptor">
              <property name="sessionFactory"><ref bean="sessionFactory"/></property>
              <!-- applicationContext hibernateInterceptor merge-point -->
          </bean>
      
          <bean id="serviceTransactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
              <property name="transactionManager"><ref bean="transactionManager"/></property>
              <property name="transactionAttributeSource">
                  <value>
                      com.myapp.deployment.service.DeploymentService.parse=PROPAGATION_REQUIRED
                  </value>
              </property>
          <!-- applicationContext serviceTransactionInterceptor merge-point -->
          </bean>
      But the question stays.... why it doesn't work with DataSourceTransactionManager?

      Comment


      • #4
        Because you MUST use the transaction manager for the chosen technology. Hibernate manages it transactions on the session not on the datasource. The session is the transactional resource here not the datasource (well in the end it is but not for your application).

        Comment


        • #5
          I can see that in your configuration of transactionAttributeSource of transactionInterceptor you have posted, is not specified what type of exception must be rolled back or commited.

          Code:
              <bean id="serviceTransactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
                  <property name="transactionManager"><ref bean="transactionManager"/></property>
                  <property name="transactionAttributeSource">
                      <value>
                          com.myapp.deployment.service.DeploymentService.parse=PROPAGATION_REQUIRED
                      </value>
                  </property>
              <!-- applicationContext serviceTransactionInterceptor merge-point -->
              </bean>
          So, looking at DataSourceTransactionManager implementation, you can find that, by default, rollback is called when the exception that is thrown must extend java.lang.RuntimeException or java.lang.Error.

          The Exception that is thrown by the Service, extends java.lang.RuntimeException or java.lang.Error ?

          Comment


          • #6
            The exception is not thrown by service, but after service call when interceptor calls flush... But anyway my problem is solved by using HibernateTransactionManager.

            Comment


            • #7
              Yes, I have read it, but in your configuration you have:

              Code:
              <value>com.myapp.deployment.service.DeploymentService.parse=PROPAGATION_REQUIRED
              </value>
              and the method parse in DeploymentService what kind of exception throw ? (that method must throw an exception to handle transaction with DataSourceTransactionManager)

              The best solution is using HibernateTransactionManager, but you ask:

              ... But the question stays.... why it doesn't work with DataSourceTransactionManager?
              and my answer is on that question (if you like, try it).

              Comment


              • #8
                The 'parse' method was throwing java.lang.Exception, and changing this to RuntimeException didn't help. But the exception which should trigger rolback was org.springframework.dao.InvalidDataAccessResourceU sageException and this is RuntimeException, and it is caught in AbstractPlatformTransactionManager.processCommit(D efaultTransactionStatus status) method. Than org.springframework.transaction.support.AbstractPl atformTransactionManager.doRollbackOnCommitExcepti on(DefaultTransactionStatus, Throwable) method is called but without expected result and without exception which could give me a hint.

                Comment


                • #9
                  That was all due to the use of the wrong transaction manager. If there is no transaction basically each query leads to a commit (i.e. multiple transactions due to the use of auto commit on the connection), so then at the point of the exception all/most data is already committed in the database.

                  Comment

                  Working...
                  X