From a617d5890203d445cbd33badcec33ddd3d9d5c0a Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 1 Apr 2021 14:47:54 +1300 Subject: [PATCH 1/5] Initial experimental support for "transparent persistence" In short, when this is turned on at flush() get any dirty beans held by the PersistenceContext and persist them (always update for these beans) --- .../src/main/java/io/ebean/Transaction.java | 8 + .../io/ebean/bean/PersistenceContext.java | 7 + .../ebeaninternal/api/ScopedTransaction.java | 5 + .../server/core/DefaultServer.java | 2 +- .../server/core/InternalConfiguration.java | 4 +- .../DefaultPersistenceContext.java | 31 ++- .../ImplicitReadOnlyTransaction.java | 5 + .../server/transaction/JdbcTransaction.java | 14 +- .../server/transaction/NoTransaction.java | 5 + .../transaction/SavepointTransaction.java | 5 + .../transaction/TransactionManager.java | 16 +- .../TransactionManagerOptions.java | 6 +- .../TestTransparentPersist.java | 204 ++++++++++++++++++ .../src/test/resources/logback-test.xml | 4 +- 14 files changed, 303 insertions(+), 13 deletions(-) create mode 100644 ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java diff --git a/ebean-api/src/main/java/io/ebean/Transaction.java b/ebean-api/src/main/java/io/ebean/Transaction.java index d4918e84e..0cbfd6e3c 100644 --- a/ebean-api/src/main/java/io/ebean/Transaction.java +++ b/ebean-api/src/main/java/io/ebean/Transaction.java @@ -59,6 +59,14 @@ public interface Transaction extends AutoCloseable { */ void register(TransactionCallback callback); + /** + * EXPERIMENTAL - turn on transparent persistence and batchMode true. + *

+ * With this turned on beans that are dirty in the persistence context + * are automatically persisted on flush() and commit(). + */ + void setTransparentPersistence(boolean transparentPersistence); + /** * Set a label on the transaction. *

diff --git a/ebean-api/src/main/java/io/ebean/bean/PersistenceContext.java b/ebean-api/src/main/java/io/ebean/bean/PersistenceContext.java index a8a42e51b..8c861af1f 100644 --- a/ebean-api/src/main/java/io/ebean/bean/PersistenceContext.java +++ b/ebean-api/src/main/java/io/ebean/bean/PersistenceContext.java @@ -1,5 +1,7 @@ package io.ebean.bean; +import java.util.List; + /** * Holds entity beans by there type and id. *

@@ -77,6 +79,11 @@ public interface PersistenceContext { */ boolean resetLimit(); + /** + * Return the list of dirty beans held by this persistence context. + */ + List dirtyBeans(); + /** * Wrapper on a bean to also indicate if a bean has been deleted. *

diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/ScopedTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/api/ScopedTransaction.java index f5a1db07b..6e95a114e 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/ScopedTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/ScopedTransaction.java @@ -131,6 +131,11 @@ public class ScopedTransaction extends SpiTransactionProxy { } } + @Override + public void setTransparentPersistence(boolean transparentPersistence) { + current.getTransaction().setTransparentPersistence(transparentPersistence); + } + @Override public void setRollbackOnly() { current.setRollbackOnly(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java index 52b94bfb6..6595d9816 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java @@ -236,7 +236,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { this.clockService = config.getClockService(); DocStoreIntegration docStoreComponents = config.createDocStoreIntegration(this); - this.transactionManager = config.createTransactionManager(docStoreComponents.updateProcessor()); + this.transactionManager = config.createTransactionManager(this, docStoreComponents.updateProcessor()); this.documentStore = docStoreComponents.documentStore(); this.queryPlanManager = config.initQueryPlanManager(transactionManager); this.metaInfoManager = new DefaultMetaInfoManager(this); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java index 8cbbbfa4b..dca8e3059 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java @@ -423,13 +423,13 @@ public class InternalConfiguration { /** * Create the TransactionManager taking into account autoCommit mode. */ - TransactionManager createTransactionManager(DocStoreUpdateProcessor indexUpdateProcessor) { + TransactionManager createTransactionManager(SpiServer server, DocStoreUpdateProcessor indexUpdateProcessor) { TransactionScopeManager scopeManager = createTransactionScopeManager(); boolean notifyL2CacheInForeground = cacheManager.isLocalL2Caching() || config.isNotifyL2CacheInForeground(); TransactionManagerOptions options = - new TransactionManagerOptions(notifyL2CacheInForeground, config, scopeManager, clusterManager, backgroundExecutor, + new TransactionManagerOptions(server, notifyL2CacheInForeground, config, scopeManager, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, dataSource(), profileHandler(), logManager, tableModState, cacheNotify, clockService); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultPersistenceContext.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultPersistenceContext.java index df92246fa..27eea2e4c 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultPersistenceContext.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultPersistenceContext.java @@ -1,11 +1,9 @@ package io.ebeaninternal.server.transaction; +import io.ebean.bean.EntityBean; import io.ebean.bean.PersistenceContext; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.locks.ReentrantLock; /** @@ -200,6 +198,20 @@ public final class DefaultPersistenceContext implements PersistenceContext { } } + @Override + public List dirtyBeans() { + lock.lock(); + try { + List list = new ArrayList<>(); + for (ClassContext classContext : typeCache.values()) { + classContext.dirtyBeans(list); + } + return list; + } finally { + lock.unlock(); + } + } + @Override public String toString() { lock.lock(); @@ -318,6 +330,17 @@ public final class DefaultPersistenceContext implements PersistenceContext { deleteSet.add(id); map.remove(id); } + + /** + * Add the dirty beans to the list. + */ + void dirtyBeans(List list) { + for (Object value : map.values()) { + if (((EntityBean) value)._ebean_getIntercept().isDirty()) { + list.add(value); + } + } + } } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java index 79bf85335..04d7a83a5 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java @@ -95,6 +95,11 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode return startNanos; } + @Override + public void setTransparentPersistence(boolean transparentPersistence) { + // do nothing + } + @Override public void setLabel(String label) { // do nothing diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java index 8c1897ff5..2585c2b23 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java @@ -187,6 +187,8 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { private final long startNanos; + private boolean transparentPersistence; + /** * Create a new JdbcTransaction. */ @@ -294,6 +296,12 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { return sb.toString(); } + @Override + public void setTransparentPersistence(boolean transparentPersistence) { + this.transparentPersistence = transparentPersistence; + this.batchMode = true; + } + @Override public boolean isSkipCacheExplicit() { return (skipCache != null && !skipCache); @@ -774,6 +782,10 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { * Flush the JDBC batch and execute derived relationship statements if necessary. */ private void internalBatchFlush() { + if (transparentPersistence) { + // Experimental - flush dirty beans held by the persistence context + manager.flushTransparent(persistenceContext, this); + } batchFlush(); if (deferredList != null) { for (PersistDeferredRelationship deferred : deferredList) { @@ -1042,7 +1054,7 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { throw new IllegalStateException(illegalStateMessage); } try { - if (queryOnly) { + if (queryOnly && !transparentPersistence) { connectionEndForQueryOnly(); } else { flushCommitAndNotify(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java index 2ef3f2058..5d593302f 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java @@ -25,6 +25,11 @@ class NoTransaction implements SpiTransaction { static final NoTransaction INSTANCE = new NoTransaction(); + @Override + public void setTransparentPersistence(boolean transparentPersistence) { + // do nothing + } + @Override public void setLabel(String label) { // do nothing diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java index b50122f5c..7b596afec 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java @@ -60,6 +60,11 @@ class SavepointTransaction extends SpiTransactionProxy { this.rollbackOnly = true; } + @Override + public void setTransparentPersistence(boolean transparentPersistence) { + throw new IllegalStateException("This is not handled yet. Need to review this case."); + } + @Override public void commit() { if (rollbackOnly) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java index e42ce2fe3..45885ad2a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java @@ -5,6 +5,7 @@ import io.ebean.ProfileLocation; import io.ebean.TxScope; import io.ebean.annotation.PersistBatch; import io.ebean.annotation.TxType; +import io.ebean.bean.PersistenceContext; import io.ebean.cache.ServerCacheNotification; import io.ebean.cache.ServerCacheNotify; import io.ebean.config.CurrentTenantProvider; @@ -17,6 +18,7 @@ import io.ebean.meta.MetricVisitor; import io.ebean.metric.MetricFactory; import io.ebean.metric.TimedMetric; import io.ebean.metric.TimedMetricMap; +import io.ebean.plugin.SpiServer; import io.ebeaninternal.api.ScopeTrans; import io.ebeaninternal.api.ScopedTransaction; import io.ebeaninternal.api.SpiLogManager; @@ -59,6 +61,8 @@ public class TransactionManager implements SpiTransactionManager { private static final Logger clusterLogger = LoggerFactory.getLogger("io.ebean.Cluster"); + private final SpiServer server; + private final BeanDescriptorManager beanDescriptorManager; /** @@ -153,7 +157,7 @@ public class TransactionManager implements SpiTransactionManager { * Create the TransactionManager */ public TransactionManager(TransactionManagerOptions options) { - + this.server = options.server; this.logManager = options.logManager; this.txnLogger = logManager.txn(); this.txnDebug = txnLogger.isDebug(); @@ -786,4 +790,14 @@ public class TransactionManager implements SpiTransactionManager { public boolean isLogSummary() { return logManager.sum().isDebug(); } + + /** + * Experimental - find dirty beans in the persistence context and persist them. + */ + public void flushTransparent(PersistenceContext persistenceContext, SpiTransaction transaction) { + List dirtyBeans = persistenceContext.dirtyBeans(); + if (!dirtyBeans.isEmpty()) { + server.updateAll(dirtyBeans, transaction); + } + } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManagerOptions.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManagerOptions.java index 9a1b0139b..5d0c87794 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManagerOptions.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManagerOptions.java @@ -3,6 +3,7 @@ package io.ebeaninternal.server.transaction; import io.ebean.BackgroundExecutor; import io.ebean.cache.ServerCacheNotify; import io.ebean.config.DatabaseConfig; +import io.ebean.plugin.SpiServer; import io.ebeaninternal.api.SpiLogManager; import io.ebeaninternal.api.SpiProfileHandler; import io.ebeaninternal.server.cluster.ClusterManager; @@ -15,6 +16,7 @@ import io.ebeanservice.docstore.api.DocStoreUpdateProcessor; */ public class TransactionManagerOptions { + final SpiServer server; final boolean notifyL2CacheInForeground; final DatabaseConfig config; final ClusterManager clusterManager; @@ -31,11 +33,11 @@ public class TransactionManagerOptions { final ClockService clockService; - public TransactionManagerOptions(boolean notifyL2CacheInForeground, DatabaseConfig config, TransactionScopeManager scopeManager, ClusterManager clusterManager, + public TransactionManagerOptions(SpiServer server, boolean notifyL2CacheInForeground, DatabaseConfig config, TransactionScopeManager scopeManager, ClusterManager clusterManager, BackgroundExecutor backgroundExecutor, DocStoreUpdateProcessor docStoreUpdateProcessor, BeanDescriptorManager descMgr, DataSourceSupplier dataSourceSupplier, SpiProfileHandler profileHandler, SpiLogManager logManager, TableModState tableModState, ServerCacheNotify cacheNotify, ClockService clockService) { - + this.server = server; this.notifyL2CacheInForeground = notifyL2CacheInForeground; this.config = config; this.scopeManager = scopeManager; diff --git a/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java new file mode 100644 index 000000000..2922d20b2 --- /dev/null +++ b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java @@ -0,0 +1,204 @@ +package org.tests.transparentpersist; + +import io.ebean.BaseTestCase; +import io.ebean.DB; +import io.ebean.Database; +import io.ebean.Transaction; +import io.ebeaninternal.api.SpiTransaction; +import io.ebeantest.LoggedSql; +import org.junit.Test; +import org.tests.model.basic.Customer; +import org.tests.model.basic.EBasicVer; +import org.tests.model.basic.Order; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestTransparentPersist extends BaseTestCase { + + @Test + public void simpleInsertUpdateDelete_experimental() { + + EBasicVer b0 = new EBasicVer("simpleIUD_0"); + b0.save(); + EBasicVer b1 = new EBasicVer("simpleIUD_1"); + b1.save(); + EBasicVer b2 = new EBasicVer("simpleIUD_2"); + b2.save(); + + EBasicVer newBean; + try (Transaction transaction = DB.beginTransaction()) { + transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + + EBasicVer found = DB.find(EBasicVer.class, b0.getId()); + found.setName("auto dirty"); + + // delete by id + DB.delete(EBasicVer.class, b1.getId()); + // find and delete, note the delete is batched up to execute later + DB.delete(DB.find(EBasicVer.class, b2.getId())); + + // insert is batched up to execute later + newBean = new EBasicVer("simpleIUD_New1"); + DB.save(newBean); + // can still mutate newBean before flush (but not after flush yet as new bean isn't put into Persistence context) + newBean.setName("simpleIUD_New2"); + + transaction.commit(); + } + + EBasicVer after = DB.find(EBasicVer.class, b0.getId()); + assertThat(after.getName()).isEqualTo("auto dirty"); + + EBasicVer wasInserted = DB.find(EBasicVer.class, newBean.getId()); + assertThat(wasInserted.getName()).isEqualTo("simpleIUD_New2"); + + assertThat(DB.find(EBasicVer.class, b1.getId())).isNull(); + assertThat(DB.find(EBasicVer.class, b2.getId())).isNull(); + + DB.delete(after); + DB.delete(wasInserted); + } + + @Test + public void simpleUpdate_experimental() { + + EBasicVer transPersist = new EBasicVer("simulate_simpleUpdate"); + transPersist.save(); + + try (Transaction transaction = DB.beginTransaction()) { + transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + + EBasicVer found = DB.find(EBasicVer.class, transPersist.getId()); + found.setName("Persisted automatically as dirty"); + + transaction.commit(); + } + + EBasicVer after = DB.find(EBasicVer.class,transPersist.getId()); + assertThat(after.getName()).isEqualTo("Persisted automatically as dirty"); + DB.delete(after); + } + + @Test + public void updateWithPersistCascadeInsert() { + + // setup data + Customer c0 = new Customer(); + c0.setName("firstCust"); + Order order = new Order(); + order.setStatus(Order.Status.NEW); + order.setCustomer(c0); + DB.save(order); + + try (Transaction transaction = DB.beginTransaction()) { + transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + + Order foundOrder = DB.find(Order.class, order.getId()); + foundOrder.setStatus(Order.Status.APPROVED); + // cascade persist will insert this customer (even though it isn't in the persistence context) + Customer c1 = new Customer(); + c1.setName("newCust CascadePersist"); + foundOrder.setCustomer(c1); + + transaction.commit(); + } + + Order checkOrder = DB.find(Order.class, order.getId()); + + assertThat(checkOrder.getStatus()).isEqualTo(Order.Status.APPROVED); + assertThat(checkOrder.getCustomer().getName()).isEqualTo("newCust CascadePersist"); + + DB.delete(checkOrder); + DB.delete(Customer.class, checkOrder.getCustomer().getId()); + DB.delete(Customer.class, c0.getId()); + } + + @Test + public void updateReferenceOnlyWithPersistCascade_Insert_andUpdateForeignKey() { + + // setup data + Customer c0 = new Customer(); + c0.setName("firstCust"); + Order order = new Order(); + order.setStatus(Order.Status.NEW); + order.setCustomer(c0); + DB.save(order); + + LoggedSql.start(); + + try (Transaction transaction = DB.beginTransaction()) { + transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + + Order foundOrder = DB.find(Order.class, order.getId()); + // we ONLY mutate the foreign key + // cascade persist will insert this customer (even though it isn't in the persistence context) + Customer c1 = new Customer(); + c1.setName("newCust CascadePersist"); + foundOrder.setCustomer(c1); + + transaction.commit(); + } + + List sql = LoggedSql.stop(); + + Order checkOrder = DB.find(Order.class, order.getId()); + + assertThat(checkOrder.getStatus()).isEqualTo(Order.Status.NEW); + assertThat(checkOrder.getCustomer().getName()).isEqualTo("newCust CascadePersist"); + + assertThat(sql).hasSize(5); + assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.order_date"); + assertThat(sql.get(1)).contains("insert into o_customer"); + assertThat(sql.get(2)).contains(" -- bind("); + assertThat(sql.get(3)).contains("update o_order set updtime=?, kcustomer_id=? where id=? and updtime=?"); + assertThat(sql.get(4)).contains(" -- bind("); + + DB.delete(checkOrder); + DB.delete(Customer.class, checkOrder.getCustomer().getId()); + DB.delete(Customer.class, c0.getId()); + } + + @Test + public void simulate_transparentPersistence_forSimpleUpdate() { + + EBasicVer transPersist = new EBasicVer("simulate_simpleUpdate"); + transPersist.save(); + + try (Transaction transaction = DB.beginTransaction()) { + transaction.setBatchMode(true); + transaction.setBatchSize(10); + + EBasicVer found = DB.find(EBasicVer.class, transPersist.getId()); + found.setName("Changed"); + + // simulate transparent persistence + List dirtyBeans = simulateTransparentPersist(transaction); + assertThat(dirtyBeans).hasSize(1); + assertThat(dirtyBeans).contains(found); + + // would occur as first part of flush + transaction.flush(); + transaction.commit(); + } + + EBasicVer after = DB.find(EBasicVer.class,transPersist.getId()); + assertThat(after.getName()).isEqualTo("Changed"); + DB.delete(after); + } + + private List simulateTransparentPersist(Transaction transaction) { + Database db = DB.getDefault(); + List dirtyBeans = getDirtyBeansFromPersistenceContext(transaction); + for (Object dirtyBean : dirtyBeans) { + db.update(dirtyBean, transaction); + } + return dirtyBeans; + } + + private List getDirtyBeansFromPersistenceContext(Transaction transaction) { + return ((SpiTransaction)transaction).getPersistenceContext().dirtyBeans(); + } + +} diff --git a/ebean-core/src/test/resources/logback-test.xml b/ebean-core/src/test/resources/logback-test.xml index 1b8a60a9b..164ff73d3 100644 --- a/ebean-core/src/test/resources/logback-test.xml +++ b/ebean-core/src/test/resources/logback-test.xml @@ -79,8 +79,8 @@ - - + + From ba397bbb0c383bb9be0d1174e3752b9db09c4ef5 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 1 Apr 2021 16:04:18 +1300 Subject: [PATCH 2/5] For experimental "transparent persistence" - Delete removes from PC early When delete bean executed with transparent persistence, this marks the bean as removed from the persistence context early. This avoids a "dirty" deleted bean from being seen as a "dirty" bean in the persistence context at flush() time. --- .../server/core/PersistRequestBean.java | 8 +++++++ .../server/persist/DefaultPersister.java | 1 + .../TestTransparentPersist.java | 23 +++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java index eb48fc2ef..c4d02cbf6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java @@ -887,6 +887,14 @@ public final class PersistRequestBean extends PersistRequest implements BeanP } } + /** + * Remove deleted beans from the persistence context early. + */ + public void removeFromPersistenceContext() { + idValue = beanDescriptor.getId(entityBean); + beanDescriptor.contextDeleted(transaction.getPersistenceContext(), idValue); + } + /** * Aggressive L1 and L2 cache cleanup for deletes. */ diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/ebean-core/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index a7b21f0c8..005e85d95 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -881,6 +881,7 @@ public final class DefaultPersister implements Persister { } int count = request.executeOrQueue(); + request.removeFromPersistenceContext(); if (request.isPersistCascade()) { deleteAssocOne(request); diff --git a/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java index 2922d20b2..be5d8329b 100644 --- a/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java +++ b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java @@ -17,6 +17,29 @@ import static org.assertj.core.api.Assertions.assertThat; public class TestTransparentPersist extends BaseTestCase { + @Test + public void delete_expect_beanRemovedFromPersistenceContext() { + + EBasicVer b0 = new EBasicVer("simpleDelete"); + DB.save(b0); + + try (Transaction transaction = DB.beginTransaction()) { + transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + + EBasicVer found = DB.find(EBasicVer.class, b0.getId()); + // make it dirty + found.setName("make it dirty"); + + // delete it, should remove it from the "live" part of persistence context + // with the expectation that no update is executed (no dirty in PC update) + DB.delete(found); + transaction.commit(); + } + + EBasicVer after = DB.find(EBasicVer.class, b0.getId()); + assertThat(after).isNull(); + } + @Test public void simpleInsertUpdateDelete_experimental() { From 0527f45f5a4e3b479296e051493cf536728bcc06 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 1 Apr 2021 16:59:03 +1300 Subject: [PATCH 3/5] For experimental "transparent persistence" - Inserts added to PC When inserting bean with transparent persistence the beans are registered with the persistence context. This is done to support the cases where the beans are inserted, a flush() occurs, the inserted bean is mutated and now dirty - we want that to be detected and get an update --- .../ebeaninternal/api/ScopedTransaction.java | 5 --- .../io/ebeaninternal/api/SpiTransaction.java | 5 +++ .../api/SpiTransactionProxy.java | 10 ++++++ .../server/core/PersistRequestBean.java | 4 +++ .../ImplicitReadOnlyTransaction.java | 5 +++ .../server/transaction/JdbcTransaction.java | 5 +++ .../server/transaction/NoTransaction.java | 5 +++ .../transaction/SavepointTransaction.java | 5 --- .../TestTransparentPersist.java | 36 +++++++++++++++++++ 9 files changed, 70 insertions(+), 10 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/ScopedTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/api/ScopedTransaction.java index 6e95a114e..f5a1db07b 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/ScopedTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/ScopedTransaction.java @@ -131,11 +131,6 @@ public class ScopedTransaction extends SpiTransactionProxy { } } - @Override - public void setTransparentPersistence(boolean transparentPersistence) { - current.getTransaction().setTransparentPersistence(transparentPersistence); - } - @Override public void setRollbackOnly() { current.setRollbackOnly(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java index 74faeccb0..8c520f79e 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java @@ -147,6 +147,11 @@ public interface SpiTransaction extends Transaction { */ int depth(); + /** + * Return true if transparent persistence is turned on. + */ + boolean isTransparentPersistence(); + /** * Return true if this transaction was created explicitly via * Ebean.beginTransaction(). diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java index fe5351ddc..1652b56f6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java @@ -43,6 +43,16 @@ public abstract class SpiTransactionProxy implements SpiTransaction { return transaction.getLabel(); } + @Override + public void setTransparentPersistence(boolean transparentPersistence) { + transaction.setTransparentPersistence(transparentPersistence); + } + + @Override + public boolean isTransparentPersistence() { + return transaction.isTransparentPersistence(); + } + @Override public void commitAndContinue() { transaction.commitAndContinue(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java index c4d02cbf6..3f7d6e79a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java @@ -1038,6 +1038,10 @@ public final class PersistRequestBean extends PersistRequest implements BeanP if (!publish) { beanDescriptor.setDraft(entityBean); } + if (transaction.isTransparentPersistence() && idValue != null) { + // with getGeneratedKeys off we will not have a idValue + beanDescriptor.contextPut(transaction.getPersistenceContext(), idValue, entityBean); + } } public boolean isReference() { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java index 04d7a83a5..a94260fb6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java @@ -100,6 +100,11 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode // do nothing } + @Override + public boolean isTransparentPersistence() { + return false; + } + @Override public void setLabel(String label) { // do nothing diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java index 2585c2b23..bb672cd33 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java @@ -302,6 +302,11 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { this.batchMode = true; } + @Override + public boolean isTransparentPersistence() { + return transparentPersistence; + } + @Override public boolean isSkipCacheExplicit() { return (skipCache != null && !skipCache); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java index 5d593302f..92f0e1ca9 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java @@ -30,6 +30,11 @@ class NoTransaction implements SpiTransaction { // do nothing } + @Override + public boolean isTransparentPersistence() { + return false; + } + @Override public void setLabel(String label) { // do nothing diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java index 7b596afec..b50122f5c 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java @@ -60,11 +60,6 @@ class SavepointTransaction extends SpiTransactionProxy { this.rollbackOnly = true; } - @Override - public void setTransparentPersistence(boolean transparentPersistence) { - throw new IllegalStateException("This is not handled yet. Need to review this case."); - } - @Override public void commit() { if (rollbackOnly) { diff --git a/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java index be5d8329b..a59ddda60 100644 --- a/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java +++ b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java @@ -17,6 +17,42 @@ import static org.assertj.core.api.Assertions.assertThat; public class TestTransparentPersist extends BaseTestCase { + @Test + public void insertFlush_mutateFlush_expect_update() { + + LoggedSql.start(); + + EBasicVer newBean; + try (Transaction transaction = DB.beginTransaction()) { + transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + + newBean = new EBasicVer("insertMe"); + DB.save(newBean); + + // flush - new bean needs to get registered into persistence context + transaction.flush(); + + // make it dirty, we expect it to execute an update on flush() + newBean.setName("make it dirty - auto save"); + + // flush again, auto persist dirty bean in persistence context + transaction.commit(); + } + + List sql = LoggedSql.stop(); + + EBasicVer found = DB.find(EBasicVer.class, newBean.getId()); + assertThat(found.getName()).isEqualTo("make it dirty - auto save"); + + assertThat(sql).hasSize(4); + assertThat(sql.get(0)).contains("insert into e_basicver"); + assertThat(sql.get(1)).contains(" -- bind("); + assertThat(sql.get(2)).contains("update e_basicver set name=?, last_update=? where id=? and last_update=?"); + assertThat(sql.get(3)).contains(" -- bind("); + + DB.delete(found); + } + @Test public void delete_expect_beanRemovedFromPersistenceContext() { From 6bcf5c6881e14b0156abaaf14fd4cff39dce8df1 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 1 Apr 2021 22:57:34 +1300 Subject: [PATCH 4/5] Add DatabaseConfig.autoPersistUpdates for experimental "transparent persistence" --- .../java/io/ebean/config/DatabaseConfig.java | 23 ++++++++++++++++++- .../server/transaction/JdbcTransaction.java | 5 ++-- .../transaction/TransactionManager.java | 11 +++++++-- .../io/ebean/config/ServerConfigTest.java | 3 +++ 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java index bf4c61675..be2ac6c1f 100644 --- a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java +++ b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java @@ -232,6 +232,12 @@ public class DatabaseConfig { */ private String historyTableSuffix = "_history"; + /** + * When true explicit transactions beans that have been made dirty will be + * automatically persisted via update on flush. + */ + private boolean autoPersistUpdates; + /** * Use for transaction scoped batch mode. */ @@ -905,6 +911,20 @@ public class DatabaseConfig { this.tenantCatalogProvider = tenantCatalogProvider; } + /** + * Return true if dirty beans are automatically persisted. + */ + public boolean isAutoPersistUpdates() { + return autoPersistUpdates; + } + + /** + * Set to true if dirty beans are automatically persisted. + */ + public void setAutoPersistUpdates(boolean autoPersistUpdates) { + this.autoPersistUpdates = autoPersistUpdates; + } + /** * Return the PersistBatch mode to use by default at the transaction level. *

@@ -2807,6 +2827,7 @@ public class DatabaseConfig { loadDocStoreSettings(p); defaultServer = p.getBoolean("defaultServer", defaultServer); + autoPersistUpdates = p.getBoolean("autoPersistUpdates", autoPersistUpdates); loadModuleInfo = p.getBoolean("loadModuleInfo", loadModuleInfo); maxCallStack = p.getInt("maxCallStack", maxCallStack); dumpMetricsOnShutdown = p.getBoolean("dumpMetricsOnShutdown", dumpMetricsOnShutdown); @@ -3348,7 +3369,7 @@ public class DatabaseConfig { this.loadModuleInfo = loadModuleInfo; } - public enum UuidVersion { + public enum UuidVersion { VERSION4, VERSION1, VERSION1RND diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java index bb672cd33..411331aef 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java @@ -211,11 +211,12 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { this.batchOnCascadeMode = false; this.onQueryOnly = OnQueryOnly.ROLLBACK; } else { + this.transparentPersistence = explicit && manager.isAutoPersistUpdates(); this.logSql = manager.isLogSql(); this.logSummary = manager.isLogSummary(); this.skipCacheAfterWrite = manager.isSkipCacheAfterWrite(); - this.batchMode = manager.getPersistBatch(); - this.batchOnCascadeMode = manager.getPersistBatchOnCascade(); + this.batchMode = manager.isPersistBatch(); + this.batchOnCascadeMode = manager.isPersistBatchOnCascade(); this.onQueryOnly = manager.getOnQueryOnly(); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java index 45885ad2a..b71868e5d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java @@ -104,6 +104,8 @@ public class TransactionManager implements SpiTransactionManager { */ final DocStoreUpdateProcessor docStoreUpdateProcessor; + private final boolean autoPersistUpdates; + private final boolean persistBatch; private final boolean persistBatchOnCascade; @@ -165,6 +167,7 @@ public class TransactionManager implements SpiTransactionManager { this.supportsSavepointId = databasePlatform.isSupportsSavepointId(); this.skipCacheAfterWrite = options.config.isSkipCacheAfterWrite(); this.notifyL2CacheInForeground = options.notifyL2CacheInForeground; + this.autoPersistUpdates = options.config.isAutoPersistUpdates(); this.persistBatch = PersistBatch.ALL == options.config.getPersistBatch(); this.persistBatchOnCascade = PersistBatch.ALL == options.config.appliedPersistBatchOnCascade(); this.rollbackOnChecked = options.config.isTransactionRollbackOnChecked(); @@ -283,11 +286,15 @@ public class TransactionManager implements SpiTransactionManager { return bulkEventListenerMap; } - boolean getPersistBatch() { + boolean isAutoPersistUpdates() { + return autoPersistUpdates; + } + + boolean isPersistBatch() { return persistBatch; } - public boolean getPersistBatchOnCascade() { + boolean isPersistBatchOnCascade() { return persistBatchOnCascade; } diff --git a/ebean-core/src/test/java/io/ebean/config/ServerConfigTest.java b/ebean-core/src/test/java/io/ebean/config/ServerConfigTest.java index f93c18d26..4e92798d6 100644 --- a/ebean-core/src/test/java/io/ebean/config/ServerConfigTest.java +++ b/ebean-core/src/test/java/io/ebean/config/ServerConfigTest.java @@ -149,6 +149,7 @@ public class ServerConfigTest { ServerConfig serverConfig = new ServerConfig(); assertTrue(serverConfig.isIdGeneratorAutomatic()); assertTrue(serverConfig.isDefaultServer()); + assertFalse(serverConfig.isAutoPersistUpdates()); serverConfig.setIdGeneratorAutomatic(false); assertFalse(serverConfig.isIdGeneratorAutomatic()); @@ -166,6 +167,8 @@ public class ServerConfigTest { serverConfig.setLoadModuleInfo(false); assertFalse(serverConfig.isAutoLoadModuleInfo()); + serverConfig.setAutoPersistUpdates(true); + assertTrue(serverConfig.isAutoPersistUpdates()); } @Test From 303039735f1cbae070cced68706a64b2dddb3bc8 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 1 Apr 2021 23:04:22 +1300 Subject: [PATCH 5/5] Refactor rename transparentPersistence to autoPersistUpdates --- .../src/main/java/io/ebean/Transaction.java | 4 ++-- .../io/ebeaninternal/api/SpiTransaction.java | 4 ++-- .../ebeaninternal/api/SpiTransactionProxy.java | 8 ++++---- .../server/core/PersistRequestBean.java | 2 +- .../transaction/ImplicitReadOnlyTransaction.java | 4 ++-- .../server/transaction/JdbcTransaction.java | 16 ++++++++-------- .../server/transaction/NoTransaction.java | 4 ++-- .../TestTransparentPersist.java | 12 ++++++------ 8 files changed, 27 insertions(+), 27 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/Transaction.java b/ebean-api/src/main/java/io/ebean/Transaction.java index 0cbfd6e3c..9a391d654 100644 --- a/ebean-api/src/main/java/io/ebean/Transaction.java +++ b/ebean-api/src/main/java/io/ebean/Transaction.java @@ -60,12 +60,12 @@ public interface Transaction extends AutoCloseable { void register(TransactionCallback callback); /** - * EXPERIMENTAL - turn on transparent persistence and batchMode true. + * EXPERIMENTAL - turn on automatic persistence of dirty beans and batchMode true. *

* With this turned on beans that are dirty in the persistence context * are automatically persisted on flush() and commit(). */ - void setTransparentPersistence(boolean transparentPersistence); + void setAutoPersistUpdates(boolean autoPersistUpdates); /** * Set a label on the transaction. diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java index 8c520f79e..8c59fa7dc 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java @@ -148,9 +148,9 @@ public interface SpiTransaction extends Transaction { int depth(); /** - * Return true if transparent persistence is turned on. + * Return true if dirty beans are automatically persisted. */ - boolean isTransparentPersistence(); + boolean isAutoPersistUpdates(); /** * Return true if this transaction was created explicitly via diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java index 1652b56f6..5fd2a3c6e 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java @@ -44,13 +44,13 @@ public abstract class SpiTransactionProxy implements SpiTransaction { } @Override - public void setTransparentPersistence(boolean transparentPersistence) { - transaction.setTransparentPersistence(transparentPersistence); + public void setAutoPersistUpdates(boolean autoPersistUpdates) { + transaction.setAutoPersistUpdates(autoPersistUpdates); } @Override - public boolean isTransparentPersistence() { - return transaction.isTransparentPersistence(); + public boolean isAutoPersistUpdates() { + return transaction.isAutoPersistUpdates(); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java index 3f7d6e79a..31d92b0a0 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java @@ -1038,7 +1038,7 @@ public final class PersistRequestBean extends PersistRequest implements BeanP if (!publish) { beanDescriptor.setDraft(entityBean); } - if (transaction.isTransparentPersistence() && idValue != null) { + if (transaction.isAutoPersistUpdates() && idValue != null) { // with getGeneratedKeys off we will not have a idValue beanDescriptor.contextPut(transaction.getPersistenceContext(), idValue, entityBean); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java index a94260fb6..5f2b5d195 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java @@ -96,12 +96,12 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode } @Override - public void setTransparentPersistence(boolean transparentPersistence) { + public void setAutoPersistUpdates(boolean autoPersistUpdates) { // do nothing } @Override - public boolean isTransparentPersistence() { + public boolean isAutoPersistUpdates() { return false; } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java index 411331aef..7d3b3ddf1 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java @@ -187,7 +187,7 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { private final long startNanos; - private boolean transparentPersistence; + private boolean autoPersistUpdates; /** * Create a new JdbcTransaction. @@ -211,7 +211,7 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { this.batchOnCascadeMode = false; this.onQueryOnly = OnQueryOnly.ROLLBACK; } else { - this.transparentPersistence = explicit && manager.isAutoPersistUpdates(); + this.autoPersistUpdates = explicit && manager.isAutoPersistUpdates(); this.logSql = manager.isLogSql(); this.logSummary = manager.isLogSummary(); this.skipCacheAfterWrite = manager.isSkipCacheAfterWrite(); @@ -298,14 +298,14 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { } @Override - public void setTransparentPersistence(boolean transparentPersistence) { - this.transparentPersistence = transparentPersistence; + public void setAutoPersistUpdates(boolean autoPersistUpdates) { + this.autoPersistUpdates = autoPersistUpdates; this.batchMode = true; } @Override - public boolean isTransparentPersistence() { - return transparentPersistence; + public boolean isAutoPersistUpdates() { + return autoPersistUpdates; } @Override @@ -788,7 +788,7 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { * Flush the JDBC batch and execute derived relationship statements if necessary. */ private void internalBatchFlush() { - if (transparentPersistence) { + if (autoPersistUpdates) { // Experimental - flush dirty beans held by the persistence context manager.flushTransparent(persistenceContext, this); } @@ -1060,7 +1060,7 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { throw new IllegalStateException(illegalStateMessage); } try { - if (queryOnly && !transparentPersistence) { + if (queryOnly && !autoPersistUpdates) { connectionEndForQueryOnly(); } else { flushCommitAndNotify(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java index 92f0e1ca9..0d3c82cd6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java @@ -26,12 +26,12 @@ class NoTransaction implements SpiTransaction { static final NoTransaction INSTANCE = new NoTransaction(); @Override - public void setTransparentPersistence(boolean transparentPersistence) { + public void setAutoPersistUpdates(boolean autoPersistUpdates) { // do nothing } @Override - public boolean isTransparentPersistence() { + public boolean isAutoPersistUpdates() { return false; } diff --git a/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java index a59ddda60..963cc1dcb 100644 --- a/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java +++ b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java @@ -24,7 +24,7 @@ public class TestTransparentPersist extends BaseTestCase { EBasicVer newBean; try (Transaction transaction = DB.beginTransaction()) { - transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + transaction.setAutoPersistUpdates(true); // EXPERIMENTAL feature newBean = new EBasicVer("insertMe"); DB.save(newBean); @@ -60,7 +60,7 @@ public class TestTransparentPersist extends BaseTestCase { DB.save(b0); try (Transaction transaction = DB.beginTransaction()) { - transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + transaction.setAutoPersistUpdates(true); // EXPERIMENTAL feature EBasicVer found = DB.find(EBasicVer.class, b0.getId()); // make it dirty @@ -88,7 +88,7 @@ public class TestTransparentPersist extends BaseTestCase { EBasicVer newBean; try (Transaction transaction = DB.beginTransaction()) { - transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + transaction.setAutoPersistUpdates(true); // EXPERIMENTAL feature EBasicVer found = DB.find(EBasicVer.class, b0.getId()); found.setName("auto dirty"); @@ -127,7 +127,7 @@ public class TestTransparentPersist extends BaseTestCase { transPersist.save(); try (Transaction transaction = DB.beginTransaction()) { - transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + transaction.setAutoPersistUpdates(true); // EXPERIMENTAL feature EBasicVer found = DB.find(EBasicVer.class, transPersist.getId()); found.setName("Persisted automatically as dirty"); @@ -152,7 +152,7 @@ public class TestTransparentPersist extends BaseTestCase { DB.save(order); try (Transaction transaction = DB.beginTransaction()) { - transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + transaction.setAutoPersistUpdates(true); // EXPERIMENTAL feature Order foundOrder = DB.find(Order.class, order.getId()); foundOrder.setStatus(Order.Status.APPROVED); @@ -188,7 +188,7 @@ public class TestTransparentPersist extends BaseTestCase { LoggedSql.start(); try (Transaction transaction = DB.beginTransaction()) { - transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + transaction.setAutoPersistUpdates(true); // EXPERIMENTAL feature Order foundOrder = DB.find(Order.class, order.getId()); // we ONLY mutate the foreign key