I have a eventhandler method that is annotated @Transactional, this method calls an implementation of an event within the same class.
This event does some checks and depending on the outcome it will either do something, or change a status and throw a RuntimeException.
In case the status is changed because of the check, I need the status to stay persisted but the event to fail for retry.
The status change method is in another class and the method is annotated with @Transactional(propagation = Propagation.REQUIRES_NEW).
I would expect that because the inner transaction completes, the status change becomes persisted and the event transaction gets rolled back.
What I am seeing is that the status change is also rolled back but I don't get why it is rolling back everything when I explicity tell it to create a new transaction for the status change.
Keep in mind this is a legacy project, so major changes in the architecture are not possible.
I tried debugging the transaction changes and the debugger does jump into the commit of the new transaction, but for some reason it is not persisted into the database.
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;
}
}
This is a rough draft of what the code is doing.
I would expect the status change to be persisted because the outer transaction gets paused when the propogation_new transaction starts. I can also see the commit being called in the transaction code of Spring but for some reason it is not persisting to the database.
If I remove the throw of the runtime exception it works but the event completes which is not desired.
What am I missing in this picture? Hope you can help.
Thx!
EDIT
I think I found the problem, changed the sample code a little bit to make it more clear.
The changeStatus changes the status of the object that gets returned by the crudService. In the real application we do a lot more changes because of objects that rely on object o also need to change on status changes.
Because the outer transaction has a state of o, does that mean that if I make changes inside the inner transaction, because the outer transaction holds a reference, it will roll back to that state instead of persisting the changes of the inner transaction?