当存在异常时,Spring @Trasactional不会回滚

时间:2018-01-05 17:29:37

标签: java spring spring-mvc jdbc transactions

我是Spring和使用Spring jdbc开发示例程序的新手。这是为了检查spring @Trsactional如何工作并在有异常的情况下将更改回滚到Db。

但我无法做到这一点。通过我在其中一个数据库更新中引发异常,它仍然将数据插入数据库而不是回滚。

我知道某个地方我犯了错误但却无法理解。不确定这是否是正确的方法。

我在做什么: -

  1. 在主要的methis中我调用了Global类的加载方法(将jdbcTemplate作为satic成员,因为我将这个jdbcTemplate用于所有其他类)

  2. 全局类加载方法将使用ApplicationContext启动bean。

  3. 在main方法中创建Dbclass实例并将jdbcTemplate作为参数发送。

  4. 4.创建一些示例数据并调用executeDb方法。

    5.execute DB方法将创建其他Dbclasss的实例并设置之前我在main方法中使用bean初始化的jdbcTemplate(我对每个操作都有单独的类 - 比如createuser,UpdataBalance等)

    1. 然后它会调用db opration方法来插入数据(我正在使用batchupdate)
    2.   

      编辑 - 删除所有try-catch

      数据库操作代码: -

      @Transactional(rollbackFor={Exception.class})
          public void executeDB(int count) throws Exception
          {
      
                      CreateAccount newacc = new CreateAccount(jdbcTemplate);
                      CreateUser newusr = new CreateUser(jdbcTemplate);
                      //BalanceUpdate newbal = new BalanceUpdate(jdbcTemplate);
                      newacc.addList(acclist);
                      newusr.addToList(usrlist);
                      //newbal.addList(ballist);
      
                      newusr.execute(); // insert data to db
                      newacc.addAccount(); // insert data to db
                      //newbal.addBalance(); // insert data to db
      
                      newacc.getAccList().clear();
                      newusr.getUserList().clear();
                      //newbal.getBalanceList().clear();
                      if(count == 5000)
                      {
                          Thread.sleep(1000);
                          throw new Exception("Rollback");
                      }
                      count += 1000;
                      //throw new Exception();
      
      
              }
      
      <!-- begin snippet: js hide: false console: true babel: false -->
      
      <!-- language: lang-xml -->
      
          <context:component-scan base-package="com.example"></context:component-scan>
      
          <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
      
          <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
              <property name="dataSource" ref="dataSource" />
          </bean>
      
          <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
              <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
              <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
              <property name="username" value="system"/>
              <property name="password" value="root"/>
          </bean>
      
      
          <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">  
          <property name="dataSource" ref="dataSource"></property>  
          </bean> 
      
          <bean id="startit" class="com.example.springtransaction.GlobalClass">  
          <property name="jdbcTemplate" ref="jdbcTemplate"></property>  
          </bean> 
      <bean id="dbupdate" class="com.example.springtransaction.DbUpdate">  
      <property name="jdbcTemplate" ref="jdbcTemplate"></property>  
      </bean>
      

2 个答案:

答案 0 :(得分:2)

您需要从方法中抛出异常,而不是在catch块中以静默方式将其记录下来。 对于已检查的例外,您需要使用@Transactional(rollbackFor = {Exception.class})http://www.logicbig.com/tutorials/spring-framework/spring-data-access-with-jdbc/transactional-roll-back/ https://www.catalysts.cc/en/wissenswertes/spring-transactional-rollback-on-checked-exceptions/

答案 1 :(得分:0)

您应该删除try-catch并定义该方法抛出异常。像这样的东西

    @Transactional(rollbackFor={Exception.class}) 
    public void executeDB() throws Exception
    {
       if(usrlist.size() >= 5) 
       { 
           CreateAccount newacc = new CreateAccount(jdbcTemplate);
           CreateUser newusr = new CreateUser(jdbcTemplate);
           BalanceUpdate newbal = new BalanceUpdate(jdbcTemplate);
           newacc.addList(acclist);
           newusr.addToList(usrlist);
           newbal.addList(ballist);
           newusr.execute(); // insert data to db
           newacc.addAccount(); // insert data to db
           newbal.addBalance(); // insert data to db - raise exception here 
        }
    }

<强>更新

包含executeDB()方法的类应该是@Component并在主类中注入该组件。 不要自己创建一个新的Dbclass()实例。

在高级别中,原因是Spring在注入声明 @Transactional 的类时会创建代理类。 您可以在此处详细了解Aspect-Oriented Programming