我有一个eventhandler方法,它被注释为@Transactional,这个方法在同一个类中调用一个事件的实现。
此事件执行一些检查,根据结果,它将执行某些操作,或者更改状态并抛出RuntimeException。
status change方法在另一个类中,并且该方法用@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的事务代码中调用了commit,但由于某种原因,它没有持久化到数据库中。
如果我移除运行时异常的抛出,它可以工作,但事件会完成,这是不需要的。
changeStatus更改由CrudService返回的对象的状态。在实际的应用程序中,我们要做更多的更改,因为依赖于object o的对象也需要在状态更改时进行更改。
因为外部事务具有o的状态,那是否意味着如果我在内部事务内部进行更改,因为外部事务持有引用,它将回滚到那个状态,而不是持久化内部事务的更改?
造成问题的原因是第一个事务持有对其状态已更改的对象的引用。
当我们在新事务中更改状态时,我们提交状态更改并返回。当我们返回时,外部事务恢复并抛出RuntimeException,这导致回滚。由于事务保存状态已更改的对象的状态,该对象将回滚到外部事务具有的状态,即旧状态。
为了解决这个问题,我不是只在新事务中进行状态更改,而是将所有逻辑移到它自己的事务中,并删除状态更改时的事务。
然后,我实现了一个检查异常,它在状态更改时被抛出,然后被捕获并抛出给父级。每一个其他异常都会被捕获并发送一个RuntimeException到Break。
异常被父级捕获,服务将抛出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;
}
}
我正在与用propagation.requires_new注释的方法的奇怪行为作斗争。 以下是TransactionManager的日志:
我的路线如下 我知道(A)处的JMS消费者将在每次轮询时分叉JMS事务,并附加到线程。(B)中的事务处理节点也将在交换到达那里并连接到线程后分叉JPA事务。 请在下面找到我的问题: > < li >能否将两个不同的事务附加到一个线程上(如上所示)? < li >如果是,哪一个应该被停职? < li> 上述路由的提交和回滚顺序应该是什么? 注:我没有从骆驼在行动第二版中找到任何明显的答案,所以请指导
问题内容: 我在EJB3无状态会话Bean中使用CMT。另外,我还创建了自己的具有注释“ @ApplicationException(rollback = true)”的异常。 要回滚事务时是否必须使用“ context.setRollbackOnly()”? 我可以通过在bean的public方法内抛出异常来回滚事务吗? 如果是这样(对Q#2的回答是“是”),我是否必须通过在方法中声明异常来将异
我正在使用spring-test运行JUnit测试,我的代码如下所示 我的问题是我希望我的测试不影响其他测试。所以我想为每个测试创建一些类似回滚的东西。我为此找了很多,但到目前为止一无所获。我使用Hibernate和MySql来实现这个
-ZJ 以下是我在Application.Properties中的数据源设置:
我在Spring Boot应用程序中有一个Javers实现。Mongo4.4被用作数据库。从MongoDB4.4开始,您可以在事务中创建文档。 我在创建对象时模拟了一个异常。如预期的那样,对象没有在数据库中创建,但是一个新的快照被添加到jv_snapshots集合中。 控制器: