#2818 - Fix Concurrent modification of listenerNotify TransactionEvent list

The issue fixed here is that SavepointTransaction was effectively using the
TransactionEvent of the underlying 'parent' transaction. The fix is for
SavepointTransaction to have its own TransactionEvent.
This commit is contained in:
Rob Bygrave
2022-09-01 22:45:17 +12:00
parent 563340edbd
commit bcc21b1c04
2 changed files with 17 additions and 0 deletions
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.transaction;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.api.SpiTransactionProxy;
import io.ebeaninternal.api.TransactionEvent;
import io.ebeaninternal.server.util.Str;
import javax.persistence.PersistenceException;
@@ -25,6 +26,7 @@ final class SavepointTransaction extends SpiTransactionProxy {
private boolean rollbackOnly;
private int state;
private TransactionEvent event;
SavepointTransaction(SpiTransaction transaction, TransactionManager manager) throws SQLException {
this.manager = manager;
@@ -40,6 +42,14 @@ final class SavepointTransaction extends SpiTransactionProxy {
this.logPrefix = transaction.getLogPrefix() + spPrefix;
}
@Override
public TransactionEvent getEvent() {
if (event == null) {
event = new TransactionEvent();
}
return event;
}
@Override
public String getLogPrefix() {
return logPrefix;
@@ -4,6 +4,8 @@ import io.ebean.*;
import io.ebean.xtest.BaseTestCase;
import io.ebean.xtest.IgnorePlatform;
import io.ebean.annotation.Platform;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.api.TransactionEvent;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.EBasic;
@@ -75,10 +77,15 @@ public class TestNestedSubTransaction extends BaseTestCase {
server.save(bean);
TransactionEvent event0 = ((SpiTransaction) txn0).getEvent();
try (Transaction txn1 = server.beginTransaction()) {
bean.setName("updateNested");
server.save(bean);
TransactionEvent event1 = ((SpiTransaction) txn1).getEvent();
assertThat(event1).isNotSameAs(event0);
try (Transaction txn2 = server.beginTransaction()) {
bean.setName("barney");
DB.save(bean);