即使提供了@ EnableTransactionManagement,@ Transactional批注也不会回滚RuntimeException [英] @Transactional annotation does not rollback RuntimeException even if @EnableTransactionManagement is provided

查看:90
本文介绍了即使提供了@ EnableTransactionManagement,@ Transactional批注也不会回滚RuntimeException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我具有以下应用程序设置:

I have the following application setup:

@SpringBootApplication
@EnableTransactionManagement
public class MyApp extends SpringBootServletInitializer {
    ...
}

具有一个具有以下内容的类:

with a class which has the following:

public class DoStaff {

    public void doStaffOnAll(List<MyObject> myObjects) {
        for (int i=0; i<myObjects.size(); i++) {
            try {
                doStaffOnSingle(myObjects.get(i), i);
            } catch (Exception e) {
                e.printStrackTrace();
            }
        }
    }

    @Transactional
    public void doStaffOnSingle(MyObject myObject, int i) {
        repository.save(myObject);
        if (i%2==0) {
            throw new RuntimeException();
        }
    }
    
}

因此,如果我使用 MyObject 的列表调用 DoStaff.doStaffOnAll ,则代码将保存列表中的所有元素,但还会为第二个元素引发运行时异常.

So if I call DoStaff.doStaffOnAll with a list of MyObjects, the code saves all element from the list but also throws a runtime exception for every second element.

由于 doStaffOnSingle 具有 @Transactional 批注,所以我希望每隔两个元素都会回滚一次.但是,如果我运行此代码,则每个元素都会成功保存在数据库中.这是为什么?我在做什么错了?

Since the doStaffOnSingle has @Transactional annotation, I would expect that every second element will be rolled back. But if I run this code, every element is saved in the DB successfully. Why is that? What am I doing wrong?

推荐答案

引用

proxy 模式(默认设置)下,仅拦截通过代理传入的外部方法调用.这意味着即使调用的方法标记有 @Transactional ,自调用(实际上是目标对象中的方法调用目标对象的另一种方法)也不会在运行时导致实际事务..另外,必须对代理进行完全初始化以提供预期的行为,因此您不应在初始化代码(即 @PostConstruct )中依赖此功能.

In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation (in effect, a method within the target object calling another method of the target object) does not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional. Also, the proxy must be fully initialized to provide the expected behavior, so you should not rely on this feature in your initialization code (that is, @PostConstruct).

doStaffOnAll()移至其他Spring组件,它将起作用.

Move the doStaffOnAll() to a different Spring component, and it'll work.

或更改为 aspectj 模式.

我建议移动方法,并设计代码,以使事务边界清晰明确,即,该类上的所有公共方法都可以启动事务,或者该类上的任何方法都不能启动事务.

I would recommend moving the method, and design the code so transaction boundaries are clear and distinct, i.e. all public methods on the class starts a transaction, or no methods on the class starts a transaction.

应该始终非常清楚您的交易边界在哪里,例如在分层设计中,通常会将 @Service 层也设置为事务层,即,从高层到服务层的任何调用都是原子事务.

It should always be very clear where your transaction boundaries are, e.g. in a layered design, you would normally make the @Service layer also be the transaction layer, i.e. any call from a higher layer to the service layer is an atomic transaction.

这篇关于即使提供了@ EnableTransactionManagement,@ Transactional批注也不会回滚RuntimeException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆