当前位置: 首页 > 知识库问答 >
问题:

@在catch块中处理错误和db插入的事务性(Spring Boot)

丁成弘
2023-03-14

我希望在出现错误时回滚数据的事务,同时将错误写入数据库。

我不能处理事务注释。

下面的代码生成一个运行时错误(1/0),并且仍然将数据写入数据库。并将数据写入错误表。

在StackOverflow中,我尝试了几种变体,并遵循类似的问题,但没有成功。

谁有一个提示,怎么办?

@Service
public class MyService{

       @Transactional(rollbackFor = Exception.class)
        public void updateData() {
            try{
                processAndPersist();    // <- db operation with inserts
                int i = 1/0; // <- Runtime error
            }catch (Exception e){
                persistError()
                trackReportError(filename, e.getMessage());
            }
        }
    
    
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void persistError(String message) {
            persistError2Db(message); // <- db operation with insert
        }

共有1个答案

程吕恭
2023-03-14

您需要在updateData()方法中抛出异常的方法来回滚事务。同时不需要回滚事务。

@Transactional(rollbackFor = Exception.class)
        public void updateData() {
            try{
                processAndPersist();    // <- db operation with inserts
                int i = 1/0; // <- Runtime error
            }catch (Exception e){
                persistError()
                trackReportError(filename, e.getMessage());
                throw ex; // if throw error here, will not work

            }
        }

仅仅抛出一个错误是没有用的,因为持久错误()将具有与updateData()相同的事务。因为使用此引用(而不是对代理的引用)调用持久性错误()

解决方案

  1. 使用自我参照。
  2. 对事务使用自注入Spring自注入
  3. updateData()(和事务)外移动的持久错误()调用。删除@Transactional持久性错误()(它将不工作),并在持久性错误2Db()中使用仓库事务
  4. 移动持久错误()到一个单独的服务器。在这种情况下,将使用代理调用它。
  5. 不要使用声明性事务(带有@Transactional注释)。使用程序化事务管理手动设置事务边界https://docs.spring.io/spring-framework/docs/3.0.0.M3/reference/html/ch11s06.html

还要记住,persistError()也会产生错误(并且很可能会产生错误)。

使用自我参照

您可以使用对MyService的自我引用来进行事务处理,因为您将能够调用的不是MyServiceImpl的方法,而是Spring代理的方法。

@Service
public class MyServiceImpl implements MyService {

    public void doWork(MyService self) {
        DataEntity data = loadData();

        try {
            self.updateData(data);
        } catch (Exception ex) {
            log.error("Error for dataId={}", data.getId(), ex);
            self.persistError("Error");
            trackReportError(filename, ex);
        }
    }

    @Transactional
    public void updateData(DataEntity data) {
        persist(data);    // <- db operation with inserts
    }

    @Transactional
    public void persistError(String message) {
        try {
            persistError2Db(message); // <- db operation with insert
        } catch (Exception ex) {
            log.error("Error for message={}", message, ex);
        }
    }
}

public interface MyService {

    void doWork(MyService self);
    
    void updateData(DataEntity data);

    void persistError(String message);

}

要使用

MyService service = ...;
service.doWork(service);
 类似资料:
  • Catch 从onError通知中恢复发射数据 Catch操作符拦截原始Observable的onError通知,将它替换为其它的数据项或数据序列,让产生的Observable能够正常终止或者根本不终止。 在某些ReactiveX的实现中,有一个叫onErrorResumeNext的操作符,它的行为与Catch相似。 RxJava将Catch实现为三个不同的操作符: onErrorReturn 让

  • 我们在SQL Server存储过程中使用以下错误处理模式: 但是当存储过程中出现以下错误时,try/catch块不起作用。 错误详细信息:存储过程试图将值插入非NULL列。 在执行存储过程中,我得到了以下错误 EXECUTE之后的事务计数表示BEGIN和COMMIT语句的数量不匹配。上一个计数=1,当前计数=0。 msg 3903, Level 16, State 1, Line 30 ROLLB

  • 这个块似乎没有捕获发生的错误,这很奇怪,考虑到我对网站的注册部分有一个类似的块。这将处理登录。该错误发生在第三行 并引发此错误: 当电子邮件格式错误时会发生这种情况,例如。因此,当它是时,我希望在块中设置错误消息。 有人知道为什么这个< code>try catch不起作用吗?

  • 不管你多么精通编程,有时我们的脚本总还是会出现错误。可能是因为我们的编写出错,或是与预期不同的用户输入,或是错误的服务端响应以及其他数千种原因。 通常,如果发生错误,脚本就会“死亡”(立即停止),并在控制台将错误打印出来。 但是有一种语法结构 try..catch,它使我们可以“捕获(catch)”错误,因此脚本可以执行更合理的操作,而不是死掉。 “try…catch” 语法 try..catch

  • 在happy path场景中,我有一个spring批处理工作,但现在我将重点放在错误处理上。 但是,在另一个测试中,我想证明一个不可预见的数据库错误会导致作业失败。为此,我创建了一个触发器,该触发器会导致对要插入的表的插入失败。 这似乎起作用了,在writer执行之后,在事务提交期间抛出异常,并且我得到以下日志消息: 这似乎也是预期的行为。问题是,这并不能阻止工作。该步骤退出到SimplyRetr

  • 我需要在我的存储过程中添加错误处理。我相信当只有一个insert语句时,通常不需要使用BEGIN TRAN/COMMIT TRAN。还有使用SET XACT_ABORT,NOCOUNT ON语句的意义是什么。请给出最佳/标准的方法将错误处理添加到下面的SP中。如果出现错误,我还需要在catch段中调用dbo.usp_get_error_info。请建议。