gpt4 book ai didi

java - @Transactional propogation_new 被父事务回滚

转载 作者:行者123 更新时间:2023-12-02 05:49:34 25 4
gpt4 key购买 nike

我有一个注释为 @Transactional 的事件处理程序方法,该方法调用同一类中事件的实现。

此事件会执行一些检查,并根据结果执行某些操作,或者更改状态并抛出 RuntimeException。

如果状态因检查而更改,我需要保持状态不变,但事件重试失败。

状态改变方法在另一个类中,该方法用@Transactional(propagation = Propagation.REQUIRES_NEW)注释。

我希望由于内部事务完成,状态更改将被持久化并且事件事务将被回滚。

我看到的是状态更改也被回滚,但我不明白为什么当我明确告诉它为状态更改创建新事务时它会回滚所有内容。

请记住,这是一个遗留项目,因此不可能对架构进行重大更改。

我尝试调试事务更改,调试器确实跳转到新事务的提交,但由于某种原因它没有持久化到数据库中。

public class t implements it {
// Do initialisation and class injection. Y is constructor injected
private final Y y;

public t(Y y) {
this.y = y;
}

@Override
@Transactional
public void handleEvent(EventContext context) {
switch (context.getEventType()) {
case event:
validate(context);
break;
}
}

private void validate(EventContext context) {
Object o = crudService.findByProperty(context.getObjectUuid());
if (!o.check) {
y.changeStatus(ERROR);
// break for retry
throw new RuntimeException("Some serious message log");
} else {
// do some stuff
}
}
}

public class Y implements IY {

@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void changeStatus(Object o, String status) {
// We do a lot more here then just change this status because of inheriting objects but for the sake of the argument, change status
o.status = status;
}
}




这是代码正在执行的操作的草稿。

我希望状态更改能够持久,因为当 propogation_new 事务启动时外部事务会暂停。我还可以看到 Spring 的事务代码中调用了提交,但由于某种原因它没有持久化到数据库。

如果我删除运行时异常的抛出,它会起作用,但事件会完成,这是不希望的。

这张照片中我缺少什么?希望您能帮忙。

谢谢!

编辑

我想我找到了问题,稍微更改了示例代码以使其更加清晰。

changeStatus 更改 crudService 返回的对象的状态。在实际应用程序中,我们做了更多的更改,因为依赖对象 o 的对象也需要根据状态更改进行更改。

因为外部事务的状态为o,这是否意味着如果我在内部事务内部进行更改,因为外部事务持有引用,它将回滚到该状态,而不是保留内部事务的更改?

最佳答案

导致该问题的原因是第一个事务持有对状态发生更改的对象的引用。

当我们更改新事务中的状态时,我们提交该状态更改并返回。当我们返回时,外部事务恢复并抛出 RuntimeException,这会导致回滚。由于事务保存了状态已更改的对象的状态,因此该对象将回滚到外部事务所具有的状态,即旧状态。

为了解决此问题,我不是仅在新事务中更改状态,而是将所有逻辑移至其自己的事务中,并删除了状态更改时的事务。

然后,我实现了一个已检查的异常,该异常在状态更改时抛出,该异常被捕获然后抛出给父级。所有其他异常都会被捕获并发送 RuntimeException 来中断。

异常被父级捕获,并且服务将抛出 RuntimeException。由于内部事务已完成并提交(在检查异常的情况下),状态保持更改,并且事件重试失败。

在我的场景中,我将逻辑移至其自己的类/方法中,您也可以将代码保留在同一个类中,但您必须实现其自身的代理并使用该代理来调用,以便通过您的方法调用 Spring 代理,否则它将忽略该方法上的事务语句。

下面是最终稿。

public class t implements it {
// Do initialisation and class injection. Y is constructor injected
private final B b;

public t(B b) {
this.b = b;
}

@Override
@Transactional
public void handleEvent(EventContext context) {
switch (context.getEventType()) {
case event:
validate(context);
break;
}
}

// You can skip this method and simply call b, but in my scenario we do a couple of other things that do not have to be part of the transaction
private void validate(EventContext context) {
try {
b.allLogicMethod(context.getObjectUuid());
} catch(Exception e) {
// Here we break the event so we can retry it, but the transaction succeeded in case it was a checked Exception
throw new RuntimeException(e);
}
}
}

public class b implements IB {

private final Y y;

Public B(Y y) {
this.Y = y;
}

@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void allLogicMethod(String uuid) {
try {
Object o = crudService.findByProperty(context.getObjectUuid());
if (!o.check) {
y.changeStatus(o, ERROR);
// break for retry
throw new CheckedException("Some serious message log");
} else {
// do everything else
}
} catch(CheckedException ce) {
throw ce;
} catch(Exception e) {
throw new RuntimeException("some message", e);
}
}
}

public class Y implements IY {

@Override
public void changeStatus(Object o, String status) {
// We do a lot more here then just change this status because of inheriting objects but for the sake of the argument, change status
o.status = status;
}
}

关于java - @Transactional propogation_new 被父事务回滚,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56062391/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com