diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java index f05964efe..db8da4d7c 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java @@ -94,7 +94,6 @@ import io.ebeaninternal.server.text.csv.TCsvReader; import io.ebeaninternal.server.transaction.DefaultPersistenceContext; import io.ebeaninternal.server.transaction.RemoteTransactionEvent; import io.ebeaninternal.server.transaction.TransactionManager; -import io.ebeaninternal.server.transaction.TransactionScopeManager; import io.ebeaninternal.util.ParamTypeHelper; import io.ebeaninternal.util.ParamTypeHelper.TypeInfo; import io.ebeanservice.docstore.api.DocStoreIntegration; @@ -132,8 +131,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { private final TransactionManager transactionManager; - private final TransactionScopeManager transactionScopeManager; - private final DataTimeZone dataTimeZone; private final CallStackFactory callStackFactory; @@ -267,7 +264,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { DocStoreIntegration docStoreComponents = config.createDocStoreIntegration(this); this.transactionManager = config.createTransactionManager(docStoreComponents.updateProcessor()); - this.transactionScopeManager = config.createTransactionScopeManager(transactionManager); this.documentStore = docStoreComponents.documentStore(); this.serverPlugins = config.getPlugins(); @@ -565,7 +561,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { */ @Override public void externalModification(TransactionEventTable tableEvent) { - SpiTransaction t = transactionScopeManager.get(); + SpiTransaction t = transactionManager.get(); if (t != null) { t.getEvent().add(tableEvent); } else { @@ -631,7 +627,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { id = desc.convertId(id); PersistenceContext pc = null; - SpiTransaction t = transactionScopeManager.get(); + SpiTransaction t = transactionManager.get(); if (t != null) { pc = t.getPersistenceContext(); Object existing = desc.contextGet(pc, id); @@ -774,7 +770,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { @Override public void scopedTransactionExit(Object returnOrThrowable, int opCode) { - ScopedTransaction st = (ScopedTransaction) transactionScopeManager.getScoped(); + ScopedTransaction st = transactionManager.getMaybeInactive(); if (st != null) { // can be null for Supports as that can start as a 'No Transaction' and then // effectively be replaced by transactions inside the scope @@ -787,7 +783,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { */ @Override public SpiTransaction currentServerTransaction() { - return transactionScopeManager.get(); + return transactionManager.get(); } /** @@ -817,10 +813,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { txScope = initTxScope(txScope); boolean setToScope = false; - ScopedTransaction txnContainer = (ScopedTransaction) transactionScopeManager.get(); + ScopedTransaction txnContainer = transactionManager.getScoped(); if (txnContainer == null) { setToScope = true; - txnContainer = new ScopedTransaction(transactionScopeManager); + txnContainer = transactionManager.createScopedTransaction(); } SpiTransaction transaction = txnContainer.current(); @@ -842,7 +838,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { txnContainer.push(new ScopeTrans(rollbackOnChecked, createTransaction, transaction, txScope)); if (setToScope) { - transactionScopeManager.set(txnContainer); + transactionManager.set(txnContainer); } return txnContainer; } @@ -884,7 +880,8 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { // start an explicit transaction SpiTransaction t = transactionManager.createTransaction(0, true, isolation.getLevel()); try { - transactionScopeManager.set(t); + // note that we are not supporting nested scoped transactions in this case + transactionManager.set(t); } catch (PersistenceException existingTransactionError) { t.end(); throw existingTransactionError; @@ -898,7 +895,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { */ @Override public Transaction currentTransaction() { - return transactionScopeManager.get(); + return transactionManager.get(); } @Override @@ -911,7 +908,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { */ @Override public void commitTransaction() { - transactionScopeManager.commit(); + transactionManager.scope().commit(); } /** @@ -919,7 +916,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { */ @Override public void rollbackTransaction() { - transactionScopeManager.rollback(); + transactionManager.scope().rollback(); } /** @@ -952,7 +949,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { */ @Override public void endTransaction() { - transactionScopeManager.end(); + transactionManager.scope().end(); } /** @@ -2152,7 +2149,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { if (t != null) { return new ObtainedTransaction((SpiTransaction) t); } - SpiTransaction trans = transactionScopeManager.get(); + SpiTransaction trans = transactionManager.get(); if (trans != null) { return new ObtainedTransaction(trans); } @@ -2162,9 +2159,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { @Override public SpiTransaction beginServerTransaction() { - SpiTransaction t = transactionManager.createTransaction(0, false, -1); - transactionScopeManager.set(t); - return t; + return transactionManager.beginServerTransaction(); } @Override diff --git a/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java b/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java index 881292bfe..e2da8f4b4 100644 --- a/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java +++ b/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java @@ -371,10 +371,11 @@ public class InternalConfiguration { */ public TransactionManager createTransactionManager(DocStoreUpdateProcessor indexUpdateProcessor) { + TransactionScopeManager scopeManager = createTransactionScopeManager(); boolean localL2 = cacheManager.isLocalL2Caching(); TransactionManagerOptions options = - new TransactionManagerOptions(localL2, serverConfig, clusterManager, backgroundExecutor, + new TransactionManagerOptions(localL2, serverConfig, scopeManager, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, dataSource(), profileHandler()); if (serverConfig.isExplicitTransactionBeginMode()) { @@ -433,18 +434,17 @@ public class InternalConfiguration { /** * Create the TransactionScopeManager taking into account JTA or external transaction manager. */ - public TransactionScopeManager createTransactionScopeManager(TransactionManager transactionManager) { + public TransactionScopeManager createTransactionScopeManager() { ExternalTransactionManager externalTransactionManager = serverConfig.getExternalTransactionManager(); if (externalTransactionManager == null && serverConfig.isUseJtaTransactionManager()) { externalTransactionManager = new JtaTransactionManager(); } if (externalTransactionManager != null) { - externalTransactionManager.setTransactionManager(transactionManager); logger.info("Using Transaction Manager [" + externalTransactionManager.getClass() + "]"); - return new ExternalTransactionScopeManager(transactionManager, externalTransactionManager); + return new ExternalTransactionScopeManager(serverConfig.getName(), externalTransactionManager); } else { - return new DefaultTransactionScopeManager(transactionManager); + return new DefaultTransactionScopeManager(serverConfig.getName()); } } diff --git a/src/main/java/io/ebeaninternal/server/transaction/DefaultTransactionScopeManager.java b/src/main/java/io/ebeaninternal/server/transaction/DefaultTransactionScopeManager.java index 0f1083346..0d54b9b22 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/DefaultTransactionScopeManager.java +++ b/src/main/java/io/ebeaninternal/server/transaction/DefaultTransactionScopeManager.java @@ -8,8 +8,13 @@ import io.ebeaninternal.api.SpiTransaction; public class DefaultTransactionScopeManager extends TransactionScopeManager { - public DefaultTransactionScopeManager(TransactionManager transactionManager) { - super(transactionManager); + public DefaultTransactionScopeManager(String serverName) { + super(serverName); + } + + @Override + public void register(TransactionManager manager) { + // do nothing } @Override @@ -23,7 +28,7 @@ public class DefaultTransactionScopeManager extends TransactionScopeManager { } @Override - public SpiTransaction getScoped() { + public SpiTransaction getMaybeInactive() { return DefaultTransactionThreadLocal.get(serverName); } diff --git a/src/main/java/io/ebeaninternal/server/transaction/ExternalTransactionScopeManager.java b/src/main/java/io/ebeaninternal/server/transaction/ExternalTransactionScopeManager.java index a3c9e57a8..c9701dc16 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/ExternalTransactionScopeManager.java +++ b/src/main/java/io/ebeaninternal/server/transaction/ExternalTransactionScopeManager.java @@ -8,18 +8,21 @@ import io.ebeaninternal.api.SpiTransaction; */ public class ExternalTransactionScopeManager extends TransactionScopeManager { - final ExternalTransactionManager externalManager; + private final ExternalTransactionManager externalManager; /** * Instantiates transaction scope manager. - * - * @param transactionManager the transaction manager */ - public ExternalTransactionScopeManager(TransactionManager transactionManager, ExternalTransactionManager externalManager) { - super(transactionManager); + public ExternalTransactionScopeManager(String serverName, ExternalTransactionManager externalManager) { + super(serverName); this.externalManager = externalManager; } + @Override + public void register(TransactionManager manager) { + externalManager.setTransactionManager(manager); + } + @Override public void commit() { DefaultTransactionThreadLocal.commit(serverName); @@ -32,7 +35,7 @@ public class ExternalTransactionScopeManager extends TransactionScopeManager { } @Override - public SpiTransaction getScoped() { + public SpiTransaction getMaybeInactive() { return get(); } diff --git a/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java b/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java index d098356a5..22c541576 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java +++ b/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java @@ -9,6 +9,7 @@ import io.ebean.event.changelog.ChangeLogListener; import io.ebean.event.changelog.ChangeLogPrepare; import io.ebean.event.changelog.ChangeSet; import io.ebean.meta.MetaTimedMetric; +import io.ebeaninternal.api.ScopedTransaction; import io.ebeaninternal.api.SpiProfileHandler; import io.ebeaninternal.api.SpiTransaction; import io.ebeaninternal.api.TransactionEvent; @@ -124,6 +125,7 @@ public class TransactionManager { private final TimedMetric txnMain; private final TimedMetric txnReadOnly; private final TimedMetricMap txnNamed; + private final TransactionScopeManager scopeManager; /** * Create the TransactionManager @@ -142,6 +144,7 @@ public class TransactionManager { this.changeLogAsync = options.config.isChangeLogAsync(); this.clusterManager = options.clusterManager; this.serverName = options.config.getName(); + this.scopeManager = options.scopeManager; this.backgroundExecutor = options.backgroundExecutor; this.dataSourceSupplier = options.dataSourceSupplier; this.docStoreActive = options.config.getDocStoreConfig().isActive(); @@ -158,6 +161,50 @@ public class TransactionManager { this.txnMain = metricFactory.createTimedMetric("txn.main"); this.txnReadOnly = metricFactory.createTimedMetric("txn.readonly"); this.txnNamed = metricFactory.createTimedMetricMap("txn.named."); + + scopeManager.register(this); + } + + /** + * Create a new scoped transaction. + */ + public ScopedTransaction createScopedTransaction() { + return new ScopedTransaction(scopeManager); + } + + /** + * Return the scope manager. + */ + public TransactionScopeManager scope() { + return scopeManager; + } + + /** + * Set the transaction onto the scope. + */ + public void set(SpiTransaction txn) { + scopeManager.set(txn); + } + + /** + * Return the current active transaction. + */ + public SpiTransaction get() { + return scopeManager.get(); + } + + /** + * Return the current active transaction as a scoped transaction. + */ + public ScopedTransaction getScoped() { + return (ScopedTransaction) scopeManager.get(); + } + + /** + * Return the current scoped transaction allowing it to be inactive (already committed or rolled back). + */ + public ScopedTransaction getMaybeInactive() { + return (ScopedTransaction)scopeManager.getMaybeInactive(); } /** @@ -478,4 +525,13 @@ public class TransactionManager { return list; } + + /** + * Begin an implicit transaction. + */ + public SpiTransaction beginServerTransaction() { + SpiTransaction t = createTransaction(0, false, -1); + scopeManager.set(t); + return t; + } } diff --git a/src/main/java/io/ebeaninternal/server/transaction/TransactionManagerOptions.java b/src/main/java/io/ebeaninternal/server/transaction/TransactionManagerOptions.java index a17de4135..87a469b80 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/TransactionManagerOptions.java +++ b/src/main/java/io/ebeaninternal/server/transaction/TransactionManagerOptions.java @@ -21,13 +21,15 @@ public class TransactionManagerOptions { final BeanDescriptorManager descMgr; final DataSourceSupplier dataSourceSupplier; final SpiProfileHandler profileHandler; + final TransactionScopeManager scopeManager; - public TransactionManagerOptions(boolean localL2Caching, ServerConfig config, ClusterManager clusterManager, - BackgroundExecutor backgroundExecutor, DocStoreUpdateProcessor docStoreUpdateProcessor, - BeanDescriptorManager descMgr, DataSourceSupplier dataSourceSupplier, SpiProfileHandler profileHandler) { + public TransactionManagerOptions(boolean localL2Caching, ServerConfig config, TransactionScopeManager scopeManager, ClusterManager clusterManager, + BackgroundExecutor backgroundExecutor, DocStoreUpdateProcessor docStoreUpdateProcessor, + BeanDescriptorManager descMgr, DataSourceSupplier dataSourceSupplier, SpiProfileHandler profileHandler) { this.localL2Caching = localL2Caching; this.config = config; + this.scopeManager = scopeManager; this.clusterManager = clusterManager; this.backgroundExecutor = backgroundExecutor; this.docStoreUpdateProcessor = docStoreUpdateProcessor; diff --git a/src/main/java/io/ebeaninternal/server/transaction/TransactionScopeManager.java b/src/main/java/io/ebeaninternal/server/transaction/TransactionScopeManager.java index 791c491bb..994a667a9 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/TransactionScopeManager.java +++ b/src/main/java/io/ebeaninternal/server/transaction/TransactionScopeManager.java @@ -8,19 +8,21 @@ import io.ebeaninternal.api.SpiTransactionScopeManager; */ public abstract class TransactionScopeManager implements SpiTransactionScopeManager { - protected final TransactionManager transactionManager; - protected final String serverName; - public TransactionScopeManager(TransactionManager transactionManager) { - this.transactionManager = transactionManager; - this.serverName = transactionManager.getServerName(); + public TransactionScopeManager(String serverName) { + this.serverName = serverName; } + /** + * Register the transaction manager (for use by external transaction scopes). + */ + public abstract void register(TransactionManager manager); + /** * Return the current Transaction allowing it to be inactive. */ - public abstract SpiTransaction getScoped(); + public abstract SpiTransaction getMaybeInactive(); /** * Return the current Transaction for this serverName and Thread.