Spring事务在抛出异常后未回滚。

3

我有一个方法的服务,该方法没有用 @Transactional 进行注解:

@Service
@RequiredArgsConstructor
public class MainService {

    private final ServiceA serviceA;    

    public void processData() {
        List<EntityA> list = serviceA.getList();
        list.forEach(item -> {
        try {
            serviceA.doSomeDbOperations(item);
        } catch(Exception e) {
            // some processing here
        } finally {
            // some processing and DB interactions here
        }
        })
    }

}

如果try块中发生异常,目的是回滚所做的更改(serviceA.doSomeDbOperations(item))。因此,我在ServiceA中用@Transactional注释了这个方法:

@Service
public class ServiceA {
    // dependencies

    @Transactional
    public void doSomeDbOperations(EntityA item) {
        // some logic here
        repositoryA.save(item)
        serviceB.deleteSomething(input)
    }
}

serviceB.deleteSomething(input)可能会抛出异常:

@Service
public class ServiceB {
    // dependencies
    
    public void deleteSomething(EntityA item) {
        // some logic here
        if(condition) {
            Throw new RuntimeException();
        }        
    }
}

问题在于当抛出异常时,try块中所做的更改不会回滚,数据不一致。你有什么想法吗?

请问您能否确认ServiceA和ServiceB是否也被标注了@Service注解? - cdr89
在默认配置下,从事务方法抛出的已检查异常不会导致回滚。 - Andrey B. Panfilov
@cdr89 是的,它们是。我更新了问题。 - MehdiB
1个回答

1

我猜在ServiceB中你使用了一个已检查的异常。

在Spring中,默认情况下只有未经检查的异常才会回滚事务,因此请尝试在您的ServiceB.deleteSomething()方法中抛出例如RuntimeException。

如果你需要在那里使用已检查的异常,你可以在你的ServiceA.doSomeDbOperations()方法中这样做:

@Transactional(rollbackFor = Throwable.class)

一些参考资料:

https://www.baeldung.com/java-checked-unchecked-exceptions

如何使Spring的@Transactional在所有未捕获异常上回滚?


我又更新了问题。实际上,我正在抛出一个RuntimeException。我还添加了rollbackFor,但是仍然存在相同的问题。 - MehdiB
如果包含rollbackFor,它应该可以工作。你在运行什么数据库?一些数据库不支持事务或未启用。 - Richard
我正在使用 PostgreSQL 11.14。 - MehdiB
@MehdiB,你的doSomeDbOperations()方法真的是public的吗?还是有其他可见性? - cdr89

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接