#1245 - Refactor internals - move logic to TransactionManager from DefaultServer

This commit is contained in:
Rob Bygrave
2018-01-31 11:56:38 +13:00
parent 5bd7853ce8
commit b682293a32
3 changed files with 133 additions and 123 deletions
@@ -26,7 +26,6 @@ import io.ebean.UpdateQuery;
import io.ebean.ValuePair;
import io.ebean.Version;
import io.ebean.annotation.TxIsolation;
import io.ebean.annotation.TxType;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.CallStack;
import io.ebean.bean.EntityBean;
@@ -55,7 +54,6 @@ import io.ebean.text.csv.CsvReader;
import io.ebean.text.json.JsonContext;
import io.ebeaninternal.api.LoadBeanRequest;
import io.ebeaninternal.api.LoadManyRequest;
import io.ebeaninternal.api.ScopeTrans;
import io.ebeaninternal.api.ScopedTransaction;
import io.ebeaninternal.api.SpiBackgroundExecutor;
import io.ebeaninternal.api.SpiEbeanServer;
@@ -135,12 +133,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
private final CallStackFactory callStackFactory;
/**
* Ebean defaults this to true but for EJB compatible behaviour set this to
* false;
*/
private final boolean rollbackOnChecked;
/**
* Handles the save, delete, updateSql CallableSql.
*/
@@ -248,8 +240,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
this.collectQueryStatsByNode = serverConfig.isCollectQueryStatsByNode();
this.callStackFactory = initCallStackFactory(serverConfig);
this.rollbackOnChecked = serverConfig.isTransactionRollbackOnChecked();
this.persister = config.createPersister(this);
this.queryEngine = config.createOrmQueryEngine();
this.relationalQueryEngine = config.createRelationalQueryEngine();
@@ -689,7 +679,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public <T> T executeCall(TxScope scope, Callable<T> c) {
ScopedTransaction scopeTrans = scopedTransaction(scope);
ScopedTransaction scopeTrans = transactionManager.beginScopedTransaction(scope);
try {
return c.call();
@@ -711,7 +701,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public void execute(TxScope scope, Runnable r) {
ScopedTransaction t = scopedTransaction(scope);
ScopedTransaction t = transactionManager.beginScopedTransaction(scope);
try {
r.run();
@@ -726,43 +716,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
}
/**
* Determine whether to create a new transaction or not.
* <p>
* This will also potentially throw exceptions for MANDATORY and NEVER types.
* </p>
*/
private boolean createNewTransaction(SpiTransaction current, TxType type) {
switch (type) {
case REQUIRED:
return current == null;
case REQUIRES_NEW:
return true;
case MANDATORY:
if (current == null) {
throw new PersistenceException("Transaction missing when MANDATORY");
}
return false;
case SUPPORTS:
return current == null;
case NEVER:
if (current != null) {
throw new PersistenceException("Transaction exists for Transactional NEVER");
}
return true; // always use NoTransaction instance
case NOT_SUPPORTED:
return true; // always use NoTransaction instance
default:
throw new RuntimeException("Should never get here?");
}
}
@Override
public void scopedTransactionEnter(TxScope txScope) {
beginTransaction(txScope);
@@ -770,12 +723,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public void scopedTransactionExit(Object returnOrThrowable, int opCode) {
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
st.complete(returnOrThrowable, opCode);
}
transactionManager.exitScopedTransaction(returnOrThrowable, opCode);
}
/**
@@ -802,71 +750,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public Transaction beginTransaction(TxScope txScope) {
return scopedTransaction(txScope);
}
/**
* Create a Scoped transaction which internally can 'nest' transactions on it's own stack.
*/
ScopedTransaction scopedTransaction(TxScope txScope) {
txScope = initTxScope(txScope);
boolean setToScope = false;
ScopedTransaction txnContainer = transactionManager.getScoped();
if (txnContainer == null) {
setToScope = true;
txnContainer = transactionManager.createScopedTransaction();
}
SpiTransaction transaction = txnContainer.current();
TxType type = txScope.getType();
boolean createTransaction = createNewTransaction(transaction, type);
if (createTransaction) {
switch (type) {
case SUPPORTS:
case NOT_SUPPORTED:
case NEVER:
transaction = NoTransaction.INSTANCE;
break;
default:
transaction = transactionManager.createTransaction(txScope.getProfileId(), true, txScope.getIsolationLevel());
initNewTransaction(transaction, txScope);
}
}
txnContainer.push(new ScopeTrans(rollbackOnChecked, createTransaction, transaction, txScope));
if (setToScope) {
transactionManager.set(txnContainer);
}
return txnContainer;
}
private void initNewTransaction(SpiTransaction transaction, TxScope txScope) {
if (txScope.isSkipCache()) {
transaction.setSkipCache(true);
}
String label = txScope.getLabel();
if (label != null) {
transaction.setLabel(label);
}
ProfileLocation profileLocation = txScope.getProfileLocation();
if (profileLocation != null) {
profileLocation.obtain();
transaction.setProfileLocation(profileLocation);
}
}
private TxScope initTxScope(TxScope txScope) {
if (txScope == null) {
return new TxScope();
} else {
// check for implied batch mode via setting batchSize
txScope.checkBatchMode();
return txScope;
}
return transactionManager.beginScopedTransaction(txScope);
}
/**
@@ -1,4 +1,4 @@
package io.ebeaninternal.server.core;
package io.ebeaninternal.server.transaction;
import io.ebean.ProfileLocation;
import io.ebean.TransactionCallback;
@@ -10,8 +10,10 @@ import io.ebean.event.changelog.ChangeSet;
import io.ebeaninternal.api.SpiProfileTransactionEvent;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.api.TransactionEvent;
import io.ebeaninternal.server.core.PersistDeferredRelationship;
import io.ebeaninternal.server.core.PersistRequest;
import io.ebeaninternal.server.core.PersistRequestBean;
import io.ebeaninternal.server.persist.BatchControl;
import io.ebeaninternal.server.transaction.ProfileStream;
import io.ebeanservice.docstore.api.DocStoreTransaction;
import javax.persistence.PersistenceException;
@@ -1,7 +1,10 @@
package io.ebeaninternal.server.transaction;
import io.ebean.BackgroundExecutor;
import io.ebean.ProfileLocation;
import io.ebean.TxScope;
import io.ebean.annotation.PersistBatch;
import io.ebean.annotation.TxType;
import io.ebean.config.CurrentTenantProvider;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DatabasePlatform.OnQueryOnly;
@@ -9,6 +12,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.ScopeTrans;
import io.ebeaninternal.api.ScopedTransaction;
import io.ebeaninternal.api.SpiProfileHandler;
import io.ebeaninternal.api.SpiTransaction;
@@ -56,6 +60,12 @@ public class TransactionManager {
protected final BeanDescriptorManager beanDescriptorManager;
/**
* Ebean defaults this to true but for EJB compatible behaviour set this to
* false;
*/
private final boolean rollbackOnChecked;
/**
* Prefix for transaction id's (logging).
*/
@@ -137,6 +147,7 @@ public class TransactionManager {
this.localL2Caching = options.localL2Caching;
this.persistBatch = options.config.getPersistBatch();
this.persistBatchOnCascade = options.config.appliedPersistBatchOnCascade();
this.rollbackOnChecked = options.config.isTransactionRollbackOnChecked();
this.beanDescriptorManager = options.descMgr;
this.viewInvalidation = options.descMgr.requiresViewEntityCacheInvalidation();
this.changeLogPrepare = options.descMgr.getChangeLogPrepare();
@@ -203,7 +214,7 @@ public class TransactionManager {
/**
* Return the current scoped transaction allowing it to be inactive (already committed or rolled back).
*/
public ScopedTransaction getMaybeInactive() {
private ScopedTransaction getMaybeInactive() {
return (ScopedTransaction)scopeManager.getMaybeInactive();
}
@@ -534,4 +545,117 @@ public class TransactionManager {
scopeManager.set(t);
return t;
}
/**
* Exit a scoped transaction (that can be inactive - already committed etc).
*/
public void exitScopedTransaction(Object returnOrThrowable, int opCode) {
ScopedTransaction st = 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
st.complete(returnOrThrowable, opCode);
}
}
/**
* Begin a scoped transaction.
*/
public ScopedTransaction beginScopedTransaction(TxScope txScope) {
txScope = initTxScope(txScope);
boolean setToScope = false;
ScopedTransaction txnContainer = getScoped();
if (txnContainer == null) {
setToScope = true;
txnContainer = createScopedTransaction();
}
SpiTransaction transaction = txnContainer.current();
TxType type = txScope.getType();
boolean createTransaction = isCreateNewTransaction(transaction, type);
if (createTransaction) {
switch (type) {
case SUPPORTS:
case NOT_SUPPORTED:
case NEVER:
transaction = NoTransaction.INSTANCE;
break;
default:
transaction = createTransaction(txScope.getProfileId(), true, txScope.getIsolationLevel());
initNewTransaction(transaction, txScope);
}
}
txnContainer.push(new ScopeTrans(rollbackOnChecked, createTransaction, transaction, txScope));
if (setToScope) {
set(txnContainer);
}
return txnContainer;
}
private void initNewTransaction(SpiTransaction transaction, TxScope txScope) {
if (txScope.isSkipCache()) {
transaction.setSkipCache(true);
}
String label = txScope.getLabel();
if (label != null) {
transaction.setLabel(label);
}
ProfileLocation profileLocation = txScope.getProfileLocation();
if (profileLocation != null) {
profileLocation.obtain();
transaction.setProfileLocation(profileLocation);
}
}
private TxScope initTxScope(TxScope txScope) {
if (txScope == null) {
return new TxScope();
} else {
// check for implied batch mode via setting batchSize
txScope.checkBatchMode();
return txScope;
}
}
/**
* Determine whether to create a new transaction or not.
* <p>
* This will also potentially throw exceptions for MANDATORY and NEVER types.
* </p>
*/
private boolean isCreateNewTransaction(SpiTransaction current, TxType type) {
switch (type) {
case REQUIRED:
return current == null;
case REQUIRES_NEW:
return true;
case MANDATORY:
if (current == null) {
throw new PersistenceException("Transaction missing when MANDATORY");
}
return false;
case SUPPORTS:
return current == null;
case NEVER:
if (current != null) {
throw new PersistenceException("Transaction exists for Transactional NEVER");
}
return true; // always use NoTransaction instance
case NOT_SUPPORTED:
return true; // always use NoTransaction instance
default:
throw new RuntimeException("Should never get here?");
}
}
}