FIX: Recursive batch flush can save dependant beans in wrong order

This commit is contained in:
Roland Praml
2023-08-08 16:59:46 +02:00
committed by Roland Praml
parent 83e87b0c67
commit d3427876b7
3 changed files with 66 additions and 16 deletions
@@ -224,14 +224,21 @@ public final class BatchControl {
* Execute all the requests contained in the list.
*/
void executeNow(ArrayList<PersistRequest> list) throws BatchedSqlException {
for (int i = 0; i < list.size(); i++) {
if (i % batchSize == 0) {
// hit the batch size so flush
flushPstmtHolder();
boolean old = transaction.isFlushOnQuery();
transaction.setFlushOnQuery(false);
// disable flush on query due transsaction callbacks
try {
for (int i = 0; i < list.size(); i++) {
if (i % batchSize == 0) {
// hit the batch size so flush
flushPstmtHolder();
}
list.get(i).executeNow();
}
list.get(i).executeNow();
flushPstmtHolder();
} finally {
transaction.setFlushOnQuery(old);
}
flushPstmtHolder();
}
public void flushOnCommit() throws BatchedSqlException {
@@ -1,23 +1,23 @@
package org.tests.batchinsert;
import io.ebean.*;
import io.ebean.xtest.BaseTestCase;
import io.ebean.xtest.IgnorePlatform;
import io.ebean.DB;
import io.ebean.Database;
import io.ebean.Transaction;
import io.ebean.annotation.PersistBatch;
import io.ebean.annotation.Platform;
import io.ebean.annotation.Transactional;
import io.ebean.meta.MetaTimedMetric;
import io.ebean.meta.ServerMetrics;
import io.ebean.test.LoggedSql;
import io.ebean.xtest.BaseTestCase;
import io.ebean.xtest.IgnorePlatform;
import io.ebean.xtest.base.DtoQuery2Test;
import io.ebeaninternal.api.SpiTransaction;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.Customer;
import org.tests.model.basic.EBasicVer;
import org.tests.model.basic.TSDetail;
import org.tests.model.basic.TSMaster;
import org.tests.model.basic.*;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@@ -25,6 +25,38 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
public class TestBatchInsertFlush extends BaseTestCase {
@Test
public void batchFlush() {
TSMaster m = new TSMaster();
m.setName("master1");
DB.save(m);
DB.getDefault().cacheManager().clearAll();
try (Transaction txn = DB.beginTransaction()) {
txn.setBatchSize(2);
txn.setBatchMode(true);
List<Customer> customers = new ArrayList<>();
for (int i = 0; i < 3; i++) {
Customer customer = ResetBasicData.createCustomer("BatchFlushPreInsert " + i, null, null, 3);
customer.addContact(new Contact("Fred" + i, "Blue"));
customers.add(customer);
}
for (int i = 3; i < 6; i++) {
Customer customer = ResetBasicData.createCustomer("BatchFlushPostInsert " + i, null, null, 3);
customer.addContact(new Contact("Fred" + i, "Blue"));
customers.add(customer);
}
DB.saveAll(customers);
txn.commit();
}
}
@Test
public void no_cascade() {
@@ -70,7 +102,7 @@ public class TestBatchInsertFlush extends BaseTestCase {
// detail
assertThat(sql.get(3)).contains("insert into t_detail_with_other_namexxxyy");
assertThat(((SpiTransaction)transaction).label()).isEqualTo("TestBatchInsertFlush.no_cascade");
assertThat(((SpiTransaction) transaction).label()).isEqualTo("TestBatchInsertFlush.no_cascade");
} finally {
transaction.end();
@@ -133,7 +165,7 @@ public class TestBatchInsertFlush extends BaseTestCase {
// trigger JDBC batch by default
DB.findDto(DtoQuery2Test.DCust.class, "select id, name from o_customer")
.findList();
.findList();
List<String> sql = LoggedSql.stop();
assertSql(sql.get(0)).contains("insert into e_basicver");
@@ -1,8 +1,10 @@
package org.tests.model.basic.event;
import io.ebean.DB;
import io.ebean.event.BeanPersistAdapter;
import io.ebean.event.BeanPersistRequest;
import org.tests.model.basic.Customer;
import org.tests.model.basic.TSMaster;
public class CustomerPersistAdapter extends BeanPersistAdapter {
@@ -16,7 +18,9 @@ public class CustomerPersistAdapter extends BeanPersistAdapter {
// StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
// request.getTransaction().log("+++++ "+Arrays.toString(stackTrace));
if (((Customer) request.bean()).getName().startsWith("BatchFlushPreInsert")) {
DB.find(TSMaster.class).where().eq("name", "master1").exists();
}
return true;
}
@@ -28,4 +32,11 @@ public class CustomerPersistAdapter extends BeanPersistAdapter {
return true;
}
@Override
public void postInsert(BeanPersistRequest<?> request) {
super.postInsert(request);
if (((Customer) request.bean()).getName().startsWith("BatchFlushPostInsert")) {
DB.find(TSMaster.class).where().eq("name", "master1").exists();
}
}
}