Announcement Announcement Module
Collapse
No announcement yet.
Transaction is committed too early Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Transaction is committed too early

    Hi,

    I have implemented 2-phase commit transaction-management successfully but I'm still experiencing some problems. I have this dbManager method that should be committed as one transaction but I'm experiencing a problem

    This is the method I'm talking about:
    Code:
       public void createPractice(TsPractice tsPractice, TfPracticeDetails tfPracticeDetails, JSONArray wtMapping) throws Exception {
            int tsPracId = ts_practiceDao.createPractice(tsPractice);
            tfPracticeDetails.setPracticeId(tsPracId);
            tf_practiceDao.createPractice(tfPracticeDetails);
            //Integer.parseInt("test");
            //this error makes sure the transaction rolls back.
            try{
                workTypeController.saveWorkTypeKeyMapping(tsPracId, wtMapping);
                webAdminAuditDbManager.addAuditLog("practice","createPractice","",tsPractice.getPrName());
            } catch (Exception e){
                throw new Exception(e);
            }
        }
    If I run this method, while the "webAdminAudit"-table isn't there for example, the method doesn't roll back the records it already inserted. Whenever an error occurs inside the dbManager (on application-level) the transaction management works fine but whenever there's a real DB-problem (error on db-level), the several inserts aren't handled as one transaction it seems. I think this is because I'm using Hibernate and I think that before the transactions get actually committed, the application checks the hibernate mapping-files and not the Databae itself. Is there a way to work around this issue? If I'm not being clear, I will try to clarify myself.
    Last edited by Duffman-; May 27th, 2010, 02:14 PM.

  • #2
    you are catching an exception and sending back a checked exception which will not roll back the transaction, do you have rollback-for setup to Exception?

    Comment


    • #3
      Hi,

      but even when I don't do the "try-catch"-construction, it still does not work ...
      no I don't have a rollback-for. This is my configuration-file:
      Code:
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:tx="http://www.springframework.org/schema/tx"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                              http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
      
          <!--DbManagers -->
          <bean id="adminWebDbManagerTarget" class="com.comp.proj.webconsole.dbmanager.AdminWebDbManager"
                scope="singleton">
              <property name="ts_adminWebDao" ref="ts_AdminWebDaoImpl"/>
              <property name="webAdminAuditDbManager" ref="webAdminAuditDbManager"/>
          </bean>
      
          <bean id="practiceDbManagerTarget" class="com.comp.proj.webconsole.dbmanager.PracticeDbManager"
                scope="singleton">
              <property name="tf_practiceDao" ref="tf_practiceDaoImpl"/>
              <property name="ts_practiceDao" ref="ts_practiceDaoImpl"/>
              <property name="workTypeController" ref="workTypeControllerImpl"/>
              <property name="webAdminAuditDbManager" ref="webAdminAuditDbManager"/>
          </bean>
          <bean id="webAdminAuditDbManagerTarget" class="com.comp.proj.webconsole.dbmanager.WebAdminAuditDbManager"
                scope="singleton">
              <constructor-arg ref="ts_AuditLogDaoImpl" index="0"/>
          </bean>
      
          <bean id="doctorDbManagerTarget" class="com.comp.proj.webconsole.dbmanager.DoctorDbManager" scope="singleton">
              <property name="tf_doctorDao" ref="tf_doctorDaoImpl"/>
              <property name="ts_doctorDao" ref="ts_doctorDaoImpl"/>
              <property name="ts_doctorFeatureDao" ref="ts_doctorFeatureListDaoImpl"/>
              <property name="webAdminAuditDbManager" ref="webAdminAuditDbManager"/>
          </bean>
      
          <bean id="facilityDbManagerTarget" class="com.comp.proj.webconsole.dbmanager.FacilityDbManager"
                scope="singleton">
              <property name="tf_facilityDao" ref="tf_facilityDaoImpl"/>
              <property name="ts_facilityDao" ref="ts_facilityDaoImpl"/>
              <property name="webAdminAuditDbManager" ref="webAdminAuditDbManager"/>
          </bean>
      
          <bean id="departmentDbManagerTarget" class="com.comp.proj.webconsole.dbmanager.DepartmentDbManager"
                scope="singleton">
              <property name="tf_departmentDao" ref="tf_departmentDaoImpl"/>
              <property name="ts_departmentDao" ref="ts_departmentDaoImpl"/>
              <property name="webAdminAuditDbManager" ref="webAdminAuditDbManager"/>
          </bean>
      
          <bean id="workTypeDbManagerTarget" class="com.comp.proj.webconsole.dbmanager.WorkTypeDbManager"
                scope="singleton">
              <property name="tf_projDmDetailsDao" ref="tf_ProjDmDetailsDaoImpl"/>
              <property name="tf_workTypeListDao" ref="tf_workTypeListDaoImpl"/>
          </bean>
      
      
          <!-- Controllers -->
          <bean id="loginControllerImpl" class="com.comp.proj.webconsole.controller.LoginControllerImpl"
                scope="singleton">
              <constructor-arg ref="adminWebDbManager" index="0"/>
          </bean>
      
          <bean id="userControllerImpl" class="com.comp.proj.webconsole.controller.UserControllerImpl" scope="singleton">
              <constructor-arg ref="adminWebDbManager" index="0"/>
          </bean>
      
          <bean id="logControllerImpl" class="com.comp.proj.webconsole.controller.LogControllerImpl" scope="singleton">
              <constructor-arg ref="webAdminAuditDbManager" index="0"/>
          </bean>
      
          <bean id="practiceControllerImpl" class="com.comp.proj.webconsole.controller.PracticeController"
                scope="singleton">
              <property name="practiceDbManager" ref="practiceDbManager"/>
              <property name="workTypeController" ref="workTypeControllerImpl"/>
          </bean>
      
          <bean id="treeController" class="com.comp.proj.webconsole.controller.TreeController" scope="singleton">
              <property name="practiceDbManager" ref="practiceDbManager"/>
              <property name="facilityDbManager" ref="facilityDbManager"/>
              <property name="departmentDbManager" ref="departmentDbManager"/>
          </bean>
      
          <bean id="doctorControllerImpl" class="com.comp.proj.webconsole.controller.DoctorControllerImpl"
                scope="singleton">
              <property name="doctorDbManager" ref="doctorDbManager"/>
              <property name="departmentDbManager" ref="departmentDbManager"/>
              <property name="facilityDbManager" ref="facilityDbManager"/>
          </bean>
      
          <bean id="facilityControllerImpl" class="com.comp.proj.webconsole.controller.FacilityControllerImpl"
                scope="singleton">
              <property name="facilityDbManager" ref="facilityDbManager"/>
          </bean>
      
          <bean id="departmentControllerImpl" class="com.comp.proj.webconsole.controller.DepartmentControllerImpl"
                scope="singleton">
              <property name="departmentDbManager" ref="departmentDbManager"/>
          </bean>
      
          <bean id="workTypeControllerImpl" class="com.comp.proj.webconsole.controller.WorkTypeControllerImpl"
                scope="singleton">
              <property name="workTypeDbManager" ref="workTypeDbManager"/>
          </bean>
      
      
          <bean id="previewController" class="com.comp.proj.publishing.controller.PreviewController"
                scope="singleton">
              <property name="processLogDao" ref="tf_processLogDao"/>
          </bean>
      
          <!-- Handlers -->
          <bean id="myLoginRedirectHandler" class="com.comp.proj.webconsole.util.MyLoginRedirectHandler"/>
      
          <!-- Servlets -->
          <bean id="previewServlet" class="com.comp.proj.publishing.servlet.PreviewServlet"
                scope="singleton">
              <property name="previewController" ref="previewController"/>
          </bean>
      
          <!-- Transaction management -->
          <bean id="adminWebDbManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
              <property name="transactionManager" ref="transactionManager"/>
              <property name="target" ref="adminWebDbManagerTarget"/>
              <property name="transactionAttributes">
                  <props>
                      <prop key="add*">PROPAGATION_REQUIRED,-Exception</prop>
                      <prop key="delete*">PROPAGATION_REQUIRED,-Exception</prop>
                  </props>
              </property>
          </bean>
      
          <bean id="departmentDbManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
              <property name="transactionManager" ref="transactionManager"/>
              <property name="target" ref="departmentDbManagerTarget"/>
              <property name="transactionAttributes">
                  <props>
                      <prop key="create*">PROPAGATION_REQUIRED,-Exception</prop>
                  </props>
              </property>
          </bean>
      
          <bean id="doctorDbManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
              <property name="transactionManager" ref="transactionManager"/>
              <property name="target" ref="doctorDbManagerTarget"/>
              <property name="transactionAttributes">
                  <props>
                      <prop key="create*">PROPAGATION_REQUIRED,-Exception</prop>
                  </props>
              </property>
          </bean>
      
          <bean id="facilityDbManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
              <property name="transactionManager" ref="transactionManager"/>
              <property name="target" ref="facilityDbManagerTarget"/>
              <property name="transactionAttributes">
                  <props>
                      <prop key="create*">PROPAGATION_REQUIRED,-Exception</prop>
                      <prop key="add*">PROPAGATION_REQUIRED,-Exception</prop>
                      <prop key="update*">PROPAGATION_REQUIRED,-Exception</prop>
                  </props>
              </property>
          </bean>
      
      
          <bean id="practiceDbManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
              <property name="transactionManager" ref="transactionManager"/>
              <property name="target" ref="practiceDbManagerTarget"/>
              <property name="transactionAttributes">
                  <props>
                      <prop key="create*">PROPAGATION_REQUIRED,-Exception</prop>
                      <prop key="update*">PROPAGATION_REQUIRED,-Exception</prop>
                  </props>
              </property>
          </bean>
      
          <bean id="webAdminAuditDbManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
              <property name="transactionManager" ref="transactionManager"/>
              <property name="target" ref="webAdminAuditDbManagerTarget"/>
              <property name="transactionAttributes">
                  <props>
                      <prop key="add*">PROPAGATION_REQUIRED,-Exception</prop>
                  </props>
              </property>
          </bean>
      
          <bean id="workTypeDbManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
              <property name="transactionManager" ref="transactionManager"/>
              <property name="target" ref="workTypeDbManagerTarget"/>
              <property name="transactionAttributes">
                  <props>
                      <prop key="add*">PROPAGATION_REQUIRED,-Exception</prop>
                  </props>
              </property>
          </bean>
      
          <bean id="jbossTransactionManager"
                class="com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple">
          </bean>
      
          <bean id="jbossUserTransaction"
                class="com.arjuna.ats.internal.jta.transaction.arjunacore.UserTransactionImple"/>
      
          <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
              <property name="transactionManager" ref="jbossTransactionManager"/>
              <property name="userTransaction" ref="jbossUserTransaction"/>
          </bean>
      </beans>

      Comment


      • #4
        http://static.springsource.org/sprin...e-rolling-back

        Comment


        • #5
          I have worked with the aop-config and tx:advice things before but I don't see how this would solve my problems.

          Comment


          • #6
            Originally posted by Duffman- View Post
            I have worked with the aop-config and tx:advice things before but I don't see how this would solve my problems.
            The link was not to make you switch to use txAdvice or aop:xxxx but to point you to the fact of this:

            "Note however that the Spring Framework's transaction infrastructure code will, by default, only mark a transaction for rollback in the case of runtime, unchecked exceptions; that is, when the thrown exception is an instance or subclass of RuntimeException. (Errors will also - by default - result in a rollback.) Checked exceptions that are thrown from a transactional method will not result in the transaction being rolled back.

            Exactly which Exception types mark a transaction for rollback can be configured. Find below a snippet of XML configuration that demonstrates how one would configure rollback for a checked, application-specific Exception type."

            You are not throwing an unchecked exception from your try/catch code but checked exception and Spring will not rollback on checked exception, only runtime...

            Comment


            • #7
              Okay,

              I get that part and removed the try-catch so it's no longer a checked exception. Thank you for the information, it was really helpful but that's not the problem that I meant in my opening thread. I'm going to try to explain myself since the first post isn't very clear.

              When I delete the table (just to test some kind of database error)that is being updated by this statement:
              Code:
                      webAdminAuditDbManager.addAuditLog("practice","createPractice","",tsPractice.getPrName());
              and there's no error while running the code, there are certain rows of the transaction that are being inserted and others that aren't. When I run this code and no error occurs, this is what happens.

              1. Hibernate: insert into comp_qa.ts_facility_details
              2. Hibernate: insert into comp_qa.webadmin_audit
              3. Hibernate: insert into proj_dev.tf_facility_details

              1 is the result of this line:
              Code:
                      int tsPracId = ts_practiceDao.createPractice(tsPractice);
              2 is the result of this line:
              Code:
                    webAdminAuditDbManager.addAuditLog("practice","createPractice","",tsPractice.getPrName());
              And the 3rd insert is the result of this line:
              Code:
                      tf_practiceDao.createPractice(tfPracticeDetails);
              However when the table "comp_qa.webadmin_audit" isn't available for some reason, the third and second insert aren't completed, but the first is. I need the first insert to be rolled back as well. I don't know why the application doesn't give a runtime exception earlier to say that the table isn't there, but I think it only checks the hibernate-mappings instead of the real database. Is there something I can do to handle this problem?

              Comment


              • #8
                And this method is transactional?

                Code:
                public void createPractice(TsPractice tsPractice, TfPracticeDetails tfPracticeDetails, JSONArray wtMapping) throws Exception {
                ...
                }

                Comment


                • #9
                  Yes,

                  whenever I do this
                  Code:
                    public void createPractice(TsPractice tsPractice, TfPracticeDetails tfPracticeDetails, JSONArray wtMapping) throws Exception {
                          int tsPracId = ts_practiceDao.createPractice(tsPractice);
                          tfPracticeDetails.setPracticeId(tsPracId);
                          tf_practiceDao.createPractice(tfPracticeDetails);
                          Integer.parseInt("test");
                          //this error makes sure the transaction rolls back.
                          workTypeController.saveWorkTypeKeyMapping(tsPracId, wtMapping);                  webAdminAuditDbManager.addAuditLog("practice","createPractice","",tsPractice.getPrName());
                      }
                  The first 2 inserts don't get committed because of the NumberFormatException I'm generating. I think that proves that the transaction is transactional.

                  You can also see it in my configuration:
                  Code:
                      <bean id="practiceDbManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
                          <property name="transactionManager" ref="transactionManager"/>
                          <property name="target" ref="practiceDbManagerTarget"/>
                          <property name="transactionAttributes">
                              <props>
                                  <prop key="create*">PROPAGATION_REQUIRED,-Exception</prop>
                                  <prop key="update*">PROPAGATION_REQUIRED,-Exception</prop>
                              </props>
                          </property>
                      </bean>
                  Thank you for giving this problem attention by the way

                  Comment


                  • #10
                    ok NumberFormatException is a runtime exception which Spring would handle for rollback. What kind of exception are you seeing when you have a missing table on your insert? If it's not a runtime exception, perhaps you can catch it and either throw a runtime exception or set the transaction for rollback only programmatically. I am guessing you are getting SQLException which is a checked exception. Are you using Spring's DB Templates (JDBC, Hibernate...) for your DB operations? Cause Spring will translate checked SQL Exception into runtime subclasses of DataAccessException. If you are not using them you will have to translate SQLException yourself into some runtime exception and throw is out to force the rollback or programmatically set the transaction status to rollback only.

                    Comment


                    • #11
                      Hi, thanks for your response.

                      this is the exception I'm getting:
                      Code:
                      org.springframework.dao.InvalidDataAccessResourceUsageException: Could not execute JDBC batch update; SQL [insert into compv35_qa.webadmin_audit (user_name, table_name, column_name, original_value, modified_value, modified_date, activity_id) values (?, ?, ?, ?, ?, ?, ?)]; nested exception is org.hibernate.exception.SQLGrammarException: Could not execute JDBC batch update
                      I guess the SQLGrammarException is a checked exception.
                      I'll try to implement the AOP-config for this or is there another way to define the checked exceptions than in the <tx:advice>? I'm off for the weekend in a couple of hours so I'll probably post an update on Monday or Tuesday.
                      Last edited by Duffman-; May 28th, 2010, 09:50 AM.

                      Comment


                      • #12
                        Hi again,

                        I've been working on the Transaction Management and still I haven't gotten it to work.
                        I think I do know what the problem is exactly now.

                        this is the method that is transactional:
                        Code:
                        public void createDoctor(TsDoctorList tsDoctorList, TsDoctorFeatureList tsDoctorFeatureList, TfDoctorDetails tfDoctorDetails) throws Exception{
                                String tsDocId = ts_doctorDao.createDoctor(tsDoctorList);
                                tsDoctorFeatureList.setDrId(tsDocId);
                                doctorFeatureListDbManager.createDoctorFeature(tsDoctorFeatureList);
                                tfDoctorDetails.setDoctorId(tsDocId);
                        
                                tf_doctorDao.createDoctor(tfDoctorDetails);
                        
                        
                        
                        
                                webAdminAuditDbManager.addAuditLog("doctor_list", "createDoctor", "", tsDoctorList.getRgLastname() + " " + tsDoctorList.getRgFirstname());
                            }
                        I have deleted a column in the table that the line "tf_doctorDao.createDoctor(tfDoctorDetails);" writes to for testing purposes, but while executing this method, only the hibernate mappings are checked. After this transactional method, the 3 transactions are being committed and only then, a database-exception is thrown. This means that the database-exceptions are thrown too late to be caught in a method that's transactional. The exception is caught on the level of the method that calls the transactional methods.
                        In my case: the transactional method "createDoctor" is called from the controller (which is not transactional) and the error is thrown at the point when the transaction is committed.

                        //Edit: my problem is very similar to this one: http://forum.springsource.org/showthread.php?t=16474
                        The thing is that I'm already using JtaTransactionManager in my configuration

                        He uses only 1 database whereas I am using two.
                        Last edited by Duffman-; Jun 4th, 2010, 03:30 PM.

                        Comment


                        • #13
                          I managed to find the problem; the table-type was MyISAM instead of InnoDB. I won't use any swearing words but this is quite frustrating.

                          Comment

                          Working...
                          X