mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#1245 - Refactor internals - move logic to TransactionManager from DefaultServer
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+4
-2
@@ -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?");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user