【问题标题】:Spring @Trasactional is not rolling back while there is an exception出现异常时,Spring @Trasactional 不会回滚
【发布时间】:2018-06-15 13:18:01
【问题描述】:

我是 Spring 新手,正在使用 Spring jdbc 编写示例程序。这是为了检查 spring @Trsactional 如何工作并在出现异常时回滚对 Db 的更改。

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

我知道我在某个地方犯了错误,但无法弄清楚。不确定这是否是正确的方法。

我在做什么:-

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

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

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

4.创建一些样本数据并调用executeDb方法。

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

  1. 然后它会调用db操作方法插入数据(我使用的是batchupdate)

编辑 - 删除所有 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>

【问题讨论】:

  • 你试过@Transactional(rollbackFor = {Exception.class})
  • @Raizuri 是的,但这没有帮助。
  • 您的代码正在吸收异常。删除 try-catch 块。
  • 如果你使用@Transactional (rollbackFor = Throwable.class) 而不是@Transactional(rollbackFor = {Exception.class}) 会怎样
  • @user7005835 - 没有区别。

标签: java spring spring-mvc jdbc transactions


【解决方案1】:

您需要从您的方法中抛出异常,而不是静默地将其记录在 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/

【讨论】:

  • @Rajarshi 您是否从您的方法中完全删除了try{} catch(Exception e){} 并添加了public void executeDB() throws Exception
  • 是的,我删除了所有 try-catch 并在 executeDB 上添加了 throws,但仍然无法正常工作
  • 很抱歉回复很晚,但我仍然无法修复它,您能否指出任何进一步可能的错误。我认为它工作正常,但我在计算结果时犯了一个小错误,同时让我觉得它正在工作
  • @Rajarshi,您能否更新问题中的代码?它说 EDIT - Removed all tr​​y-catchtry{} catch{} 仍然存在。
  • 我还添加了项目的 github url。我想这将有助于轻松识别问题
【解决方案2】:

您应该删除 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 的更多信息。

【讨论】:

  • 我已经删除了所有的try-catch,仍然无法正常工作
  • 你怎么称呼那个方法?您应该从注入的 bean 中调用它。
  • 我的意思是这个方法应该在 @Component 中,并在主类中注入该组件。不要自己创建一个新的 Dbclass() 实例。
  • 对不起,我在检查 Db 中的实际细节时犯了一个错误。但不幸的是,它并没有回滚。例如,我在插入 5000 条记录后抛出了一个异常,但它并没有回滚到 4900 条。
猜你喜欢
  • 1970-01-01
  • 2019-06-30
  • 1970-01-01
  • 2013-05-01
  • 1970-01-01
  • 2016-08-14
  • 2018-11-26
  • 1970-01-01
  • 2019-04-30
相关资源
最近更新 更多