mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#991 ENH: Add forUpdateNoWait() and forUpdateSkipLocked() options ... #528 ENH: Improve exception handling
This commit is contained in:
@@ -4,6 +4,8 @@ import io.ebean.QueryIterator;
|
||||
import io.ebean.Version;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -55,4 +57,9 @@ public interface OrmQueryEngine {
|
||||
* Execute the query as a update statement.
|
||||
*/
|
||||
<T> int update(OrmQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Translate the SQLException to a specific persistence exception type if possible.
|
||||
*/
|
||||
<T> PersistenceException translate(OrmQueryRequest<T> request, String bindLog, String sql, SQLException e);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import io.ebeaninternal.server.query.CancelableQuery;
|
||||
import io.ebeaninternal.server.transaction.DefaultPersistenceContext;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -76,6 +77,10 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
this.readOnly = query.isReadOnly();
|
||||
}
|
||||
|
||||
public PersistenceException translate(String bindLog, String sql, SQLException e) {
|
||||
return queryEngine.translate(this, bindLog, sql, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the transaction as not being query only.
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,7 @@ import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
import io.ebeaninternal.server.persist.BatchControl;
|
||||
import io.ebeaninternal.server.persist.BatchPostExecute;
|
||||
import io.ebeaninternal.server.persist.BatchedSqlException;
|
||||
import io.ebeaninternal.server.persist.PersistExecute;
|
||||
|
||||
/**
|
||||
@@ -15,14 +16,14 @@ public abstract class PersistRequest extends BeanRequest implements BatchPostExe
|
||||
INSERT, UPDATE, DELETE, SOFT_DELETE, DELETE_PERMANENT, UPDATESQL, CALLABLESQL
|
||||
}
|
||||
|
||||
protected boolean persistCascade;
|
||||
boolean persistCascade;
|
||||
|
||||
/**
|
||||
* One of INSERT, UPDATE, DELETE, UPDATESQL or CALLABLESQL.
|
||||
*/
|
||||
protected Type type;
|
||||
|
||||
protected final PersistExecute persistExecute;
|
||||
final PersistExecute persistExecute;
|
||||
|
||||
/**
|
||||
* Used by CallableSqlRequest and UpdateSqlRequest.
|
||||
@@ -63,24 +64,27 @@ public abstract class PersistRequest extends BeanRequest implements BatchPostExe
|
||||
/**
|
||||
* Execute the statement.
|
||||
*/
|
||||
public int executeStatement() {
|
||||
int executeStatement() {
|
||||
|
||||
boolean batch = isBatchThisRequest();
|
||||
|
||||
int rows;
|
||||
BatchControl control = transaction.getBatchControl();
|
||||
if (control != null) {
|
||||
rows = control.executeStatementOrBatch(this, batch);
|
||||
try {
|
||||
int rows;
|
||||
BatchControl control = transaction.getBatchControl();
|
||||
if (control != null) {
|
||||
rows = control.executeStatementOrBatch(this, batch);
|
||||
|
||||
} else if (batch) {
|
||||
// need to create the BatchControl
|
||||
control = persistExecute.createBatchControl(transaction);
|
||||
rows = control.executeStatementOrBatch(this, true);
|
||||
} else {
|
||||
rows = executeNow();
|
||||
} else if (batch) {
|
||||
// need to create the BatchControl
|
||||
control = persistExecute.createBatchControl(transaction);
|
||||
rows = control.executeStatementOrBatch(this, true);
|
||||
} else {
|
||||
rows = executeNow();
|
||||
}
|
||||
return rows;
|
||||
} catch (BatchedSqlException e) {
|
||||
throw transaction.translate(e.getMessage(), e.getCause());
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
public void initTransIfRequired() {
|
||||
|
||||
@@ -20,6 +20,7 @@ import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import io.ebeaninternal.server.deploy.id.ImportedId;
|
||||
import io.ebeaninternal.server.persist.BatchControl;
|
||||
import io.ebeaninternal.server.persist.BatchedSqlException;
|
||||
import io.ebeaninternal.server.persist.PersistExecute;
|
||||
import io.ebeaninternal.server.transaction.BeanPersistIdMap;
|
||||
import io.ebeanservice.docstore.api.DocStoreUpdate;
|
||||
@@ -499,10 +500,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
}
|
||||
}
|
||||
|
||||
public BeanManager<T> getBeanManager() {
|
||||
return beanManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor for the associated bean.
|
||||
*/
|
||||
@@ -697,17 +694,20 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
public int executeOrQueue() {
|
||||
|
||||
boolean batch = isBatchThisRequest();
|
||||
try {
|
||||
BatchControl control = transaction.getBatchControl();
|
||||
if (control != null) {
|
||||
return control.executeOrQueue(this, batch);
|
||||
}
|
||||
if (batch) {
|
||||
control = persistExecute.createBatchControl(transaction);
|
||||
return control.executeOrQueue(this, true);
|
||||
|
||||
BatchControl control = transaction.getBatchControl();
|
||||
if (control != null) {
|
||||
return control.executeOrQueue(this, batch);
|
||||
}
|
||||
if (batch) {
|
||||
control = persistExecute.createBatchControl(transaction);
|
||||
return control.executeOrQueue(this, true);
|
||||
|
||||
} else {
|
||||
return executeNow();
|
||||
} else {
|
||||
return executeNow();
|
||||
}
|
||||
} catch (BatchedSqlException e) {
|
||||
throw transaction.translate(e.getMessage(), e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -419,6 +419,21 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
return query.filterMany(prop);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdate() {
|
||||
return query.forUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateNoWait() {
|
||||
return query.forUpdateNoWait();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateSkipLocked() {
|
||||
return query.forUpdateSkipLocked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> select(String fetchProperties) {
|
||||
return query.select(fetchProperties);
|
||||
|
||||
@@ -419,6 +419,21 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
return exprList.findUnique();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdate() {
|
||||
return exprList.forUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateNoWait() {
|
||||
return exprList.forUpdateNoWait();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateSkipLocked() {
|
||||
return exprList.forUpdateSkipLocked();
|
||||
}
|
||||
|
||||
/**
|
||||
* Path exists - for the given path in a JSON document.
|
||||
*/
|
||||
|
||||
@@ -5,7 +5,6 @@ import io.ebeaninternal.server.core.PersistRequest;
|
||||
import io.ebeaninternal.server.core.PersistRequestBean;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@@ -123,7 +122,7 @@ public final class BatchControl {
|
||||
* to the depth.
|
||||
* </p>
|
||||
*/
|
||||
public int executeStatementOrBatch(PersistRequest request, boolean batch) {
|
||||
public int executeStatementOrBatch(PersistRequest request, boolean batch) throws BatchedSqlException {
|
||||
if (!batch || (batchFlushOnMixed && !isBeansEmpty())) {
|
||||
// flush when mixing beans and updateSql
|
||||
flush();
|
||||
@@ -148,7 +147,7 @@ public final class BatchControl {
|
||||
* immediately or queue it for batch processing later. The queue is flushedIntercept
|
||||
* according to the depth (object graph depth).
|
||||
*/
|
||||
public int executeOrQueue(PersistRequestBean<?> request, boolean batch) {
|
||||
public int executeOrQueue(PersistRequestBean<?> request, boolean batch) throws BatchedSqlException {
|
||||
|
||||
if (!batch || (batchFlushOnMixed && !pstmtHolder.isEmpty())) {
|
||||
// flush when mixing beans and updateSql
|
||||
@@ -167,7 +166,7 @@ public final class BatchControl {
|
||||
/**
|
||||
* Add the request to the batch and return true if we should flush.
|
||||
*/
|
||||
private boolean addToBatch(PersistRequestBean<?> request) {
|
||||
private boolean addToBatch(PersistRequestBean<?> request) throws BatchedSqlException {
|
||||
|
||||
BatchedBeanHolder beanHolder = getBeanHolder(request);
|
||||
int bufferSize = beanHolder.append(request);
|
||||
@@ -193,14 +192,14 @@ public final class BatchControl {
|
||||
/**
|
||||
* Flush any batched PreparedStatements.
|
||||
*/
|
||||
protected void flushPstmtHolder() {
|
||||
protected void flushPstmtHolder() throws BatchedSqlException {
|
||||
pstmtHolder.flush(getGeneratedKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute all the requests contained in the list.
|
||||
*/
|
||||
protected void executeNow(ArrayList<PersistRequest> list) {
|
||||
protected 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
|
||||
@@ -214,14 +213,14 @@ public final class BatchControl {
|
||||
/**
|
||||
* Flush without resetting the topOrder (maintains the depth info).
|
||||
*/
|
||||
public void flush() throws PersistenceException {
|
||||
public void flush() throws BatchedSqlException {
|
||||
flush(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush with a reset the topOrder (fully empty the batch).
|
||||
*/
|
||||
public void flushReset() throws PersistenceException {
|
||||
public void flushReset() throws BatchedSqlException {
|
||||
flush(true);
|
||||
}
|
||||
|
||||
@@ -236,31 +235,38 @@ public final class BatchControl {
|
||||
/**
|
||||
* execute all the requests currently queued or batched.
|
||||
*/
|
||||
private void flush(boolean resetTop) throws PersistenceException {
|
||||
private void flush(boolean resetTop) throws BatchedSqlException {
|
||||
|
||||
if (!pstmtHolder.isEmpty()) {
|
||||
// Flush existing pstmts (updateSql or callableSql)
|
||||
flushPstmtHolder();
|
||||
}
|
||||
if (isEmpty()) {
|
||||
// Nothing in queue to flush
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (!pstmtHolder.isEmpty()) {
|
||||
// Flush existing pstmts (updateSql or callableSql)
|
||||
flushPstmtHolder();
|
||||
}
|
||||
if (isEmpty()) {
|
||||
// Nothing in queue to flush
|
||||
return;
|
||||
}
|
||||
|
||||
// convert entry map to array for sorting
|
||||
BatchedBeanHolder[] bsArray = getBeanHolderArray();
|
||||
// sort the entries by depth
|
||||
Arrays.sort(bsArray, depthComparator);
|
||||
// convert entry map to array for sorting
|
||||
BatchedBeanHolder[] bsArray = getBeanHolderArray();
|
||||
// sort the entries by depth
|
||||
Arrays.sort(bsArray, depthComparator);
|
||||
|
||||
if (transaction.isLogSummary()) {
|
||||
transaction.logSummary("BatchControl flush " + Arrays.toString(bsArray));
|
||||
}
|
||||
for (BatchedBeanHolder aBsArray : bsArray) {
|
||||
aBsArray.executeNow();
|
||||
}
|
||||
if (transaction.isLogSummary()) {
|
||||
transaction.logSummary("BatchControl flush " + Arrays.toString(bsArray));
|
||||
}
|
||||
for (BatchedBeanHolder aBsArray : bsArray) {
|
||||
aBsArray.executeNow();
|
||||
}
|
||||
|
||||
if (resetTop) {
|
||||
beanHoldMap.clear();
|
||||
if (resetTop) {
|
||||
beanHoldMap.clear();
|
||||
}
|
||||
} catch (BatchedSqlException e) {
|
||||
// clear the batch on error in case we want to
|
||||
// catch, rollback and continue processing
|
||||
clear();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,7 +274,7 @@ public final class BatchControl {
|
||||
* Return an entry for the given type description. The type description is
|
||||
* typically the bean class name (or table name for MapBeans).
|
||||
*/
|
||||
private BatchedBeanHolder getBeanHolder(PersistRequestBean<?> request) {
|
||||
private BatchedBeanHolder getBeanHolder(PersistRequestBean<?> request) throws BatchedSqlException {
|
||||
|
||||
BeanDescriptor<?> beanDescriptor = request.getBeanDescriptor();
|
||||
BatchedBeanHolder batchBeanHolder = beanHoldMap.get(beanDescriptor.getFullName());
|
||||
|
||||
@@ -79,7 +79,7 @@ public class BatchedBeanHolder {
|
||||
* and then execute them.
|
||||
* </p>
|
||||
*/
|
||||
public void executeNow() {
|
||||
public void executeNow() throws BatchedSqlException {
|
||||
// process the requests. Creates one or more PreparedStatements
|
||||
// with binding addBatch() for each request.
|
||||
// Note updates and deletes can result in many PreparedStatements
|
||||
|
||||
@@ -121,7 +121,7 @@ public class BatchedPstmt {
|
||||
list.get(index).setGeneratedKey(idValue);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ public class BatchedPstmtHolder {
|
||||
*
|
||||
* @param getGeneratedKeys if true try to get generated keys for inserts
|
||||
*/
|
||||
public void flush(boolean getGeneratedKeys) throws PersistenceException {
|
||||
public void flush(boolean getGeneratedKeys) throws BatchedSqlException {
|
||||
|
||||
SQLException firstError = null;
|
||||
String errorSql = null;
|
||||
@@ -96,7 +96,7 @@ public class BatchedPstmtHolder {
|
||||
} catch (SQLException ex) {
|
||||
SQLException next = ex.getNextException();
|
||||
while (next != null) {
|
||||
logger.error("Next Exception during batch execution", next);
|
||||
logger.trace("Next Exception during batch execution", next);
|
||||
next = next.getNextException();
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ public class BatchedPstmtHolder {
|
||||
|
||||
if (firstError != null) {
|
||||
String msg = "Error when batch flush on sql: " + errorSql;
|
||||
throw new PersistenceException(msg, firstError);
|
||||
throw new BatchedSqlException(msg, firstError);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package io.ebeaninternal.server.persist;
|
||||
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Holds the first SQLException found when executing a JDBC batch.
|
||||
*/
|
||||
public class BatchedSqlException extends Exception {
|
||||
|
||||
private SQLException cause;
|
||||
|
||||
BatchedSqlException(String message, SQLException cause) {
|
||||
super(message, cause);
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLException getCause() {
|
||||
return cause;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
package io.ebeaninternal.server.persist.dml;
|
||||
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.util.StringHelper;
|
||||
import io.ebeaninternal.server.core.PersistRequestBean;
|
||||
import io.ebeaninternal.server.persist.BeanPersister;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
@@ -18,15 +18,16 @@ import java.sql.SQLException;
|
||||
*/
|
||||
public final class DmlBeanPersister implements BeanPersister {
|
||||
|
||||
private final DatabasePlatform dbPlatform;
|
||||
|
||||
private final UpdateMeta updateMeta;
|
||||
|
||||
private final InsertMeta insertMeta;
|
||||
|
||||
private final DeleteMeta deleteMeta;
|
||||
|
||||
|
||||
public DmlBeanPersister(UpdateMeta updateMeta, InsertMeta insertMeta, DeleteMeta deleteMeta) {
|
||||
|
||||
public DmlBeanPersister(DatabasePlatform dbPlatform, UpdateMeta updateMeta, InsertMeta insertMeta, DeleteMeta deleteMeta) {
|
||||
this.dbPlatform = dbPlatform;
|
||||
this.updateMeta = updateMeta;
|
||||
this.insertMeta = insertMeta;
|
||||
this.deleteMeta = deleteMeta;
|
||||
@@ -37,9 +38,7 @@ public final class DmlBeanPersister implements BeanPersister {
|
||||
*/
|
||||
@Override
|
||||
public int delete(PersistRequestBean<?> request) {
|
||||
|
||||
DeleteHandler delete = new DeleteHandler(request, deleteMeta);
|
||||
return execute(request, delete);
|
||||
return execute(request, new DeleteHandler(request, deleteMeta));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,9 +46,7 @@ public final class DmlBeanPersister implements BeanPersister {
|
||||
*/
|
||||
@Override
|
||||
public void insert(PersistRequestBean<?> request) {
|
||||
|
||||
InsertHandler insert = new InsertHandler(request, insertMeta);
|
||||
execute(request, insert);
|
||||
execute(request, new InsertHandler(request, insertMeta));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,9 +54,7 @@ public final class DmlBeanPersister implements BeanPersister {
|
||||
*/
|
||||
@Override
|
||||
public void update(PersistRequestBean<?> request) {
|
||||
|
||||
UpdateHandler update = new UpdateHandler(request, updateMeta);
|
||||
execute(request, update);
|
||||
execute(request, new UpdateHandler(request, updateMeta));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,12 +75,12 @@ public final class DmlBeanPersister implements BeanPersister {
|
||||
|
||||
} catch (SQLException e) {
|
||||
// log the error to the transaction log
|
||||
String errMsg = StringHelper.replaceStringMulti(e.getMessage(), new String[]{"\r", "\n"}, "\\n ");
|
||||
String msg = "ERROR executing DML bindLog[" + handler.getBindLog() + "] error[" + errMsg + "]";
|
||||
String errMsg = StringHelper.replaceStringMulti(e.getMessage(), new String[]{"\r", "\n"}, " ");
|
||||
String msg = "Error[" + errMsg + "]";
|
||||
if (request.getTransaction().isLogSummary()) {
|
||||
request.getTransaction().logSummary(msg);
|
||||
}
|
||||
throw new PersistenceException(msg, e);
|
||||
throw dbPlatform.translate(msg, e);
|
||||
|
||||
} finally {
|
||||
if (!batched) {
|
||||
|
||||
@@ -10,9 +10,12 @@ import io.ebeaninternal.server.persist.BeanPersisterFactory;
|
||||
*/
|
||||
public class DmlBeanPersisterFactory implements BeanPersisterFactory {
|
||||
|
||||
private final DatabasePlatform dbPlatform;
|
||||
|
||||
private final MetaFactory metaFactory;
|
||||
|
||||
public DmlBeanPersisterFactory(DatabasePlatform dbPlatform) {
|
||||
this.dbPlatform = dbPlatform;
|
||||
this.metaFactory = new MetaFactory(dbPlatform);
|
||||
}
|
||||
|
||||
@@ -29,7 +32,7 @@ public class DmlBeanPersisterFactory implements BeanPersisterFactory {
|
||||
UpdateMeta updMeta = metaFactory.createUpdate(desc);
|
||||
DeleteMeta delMeta = metaFactory.createDelete(desc);
|
||||
InsertMeta insMeta = metaFactory.createInsert(desc);
|
||||
return new DmlBeanPersister(updMeta, insMeta, delMeta);
|
||||
return new DmlBeanPersister(dbPlatform, updMeta, insMeta, delMeta);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,12 +10,10 @@ import io.ebean.bean.NodeUsageListener;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.event.readaudit.ReadEvent;
|
||||
import io.ebean.util.StringHelper;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.api.SpiQuery.Mode;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
import io.ebeaninternal.server.autotune.ProfilingListener;
|
||||
import io.ebeaninternal.server.core.Message;
|
||||
import io.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import io.ebeaninternal.server.core.SpiOrmQueryRequest;
|
||||
import io.ebeaninternal.server.deploy.BeanCollectionHelp;
|
||||
@@ -665,28 +663,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
* Create a PersistenceException including interesting information like the bindLog and sql used.
|
||||
*/
|
||||
PersistenceException createPersistenceException(SQLException e) {
|
||||
|
||||
return createPersistenceException(e, getTransaction(), bindLog, sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a PersistenceException including interesting information like the bindLog and sql used.
|
||||
*/
|
||||
static PersistenceException createPersistenceException(SQLException e, SpiTransaction t, String bindLog, String sql) {
|
||||
|
||||
if (t.isLogSummary()) {
|
||||
// log the error to the transaction log
|
||||
String errMsg = StringHelper.replaceStringMulti(e.getMessage(), new String[]{"\r", "\n"}, "\\n ");
|
||||
String msg = "ERROR executing query: bindLog[" + bindLog + "] error[" + errMsg + "]";
|
||||
t.logSummary(msg);
|
||||
}
|
||||
|
||||
// ensure 'rollback' is logged if queryOnly transaction
|
||||
t.getConnection();
|
||||
|
||||
// build a decent error message for the exception
|
||||
String m = Message.msg("fetch.sqlerror", e.getMessage(), bindLog, sql);
|
||||
return new PersistenceException(m, e);
|
||||
return request.translate(bindLog, sql, e);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,8 +8,11 @@ import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.util.StringHelper;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
import io.ebeaninternal.server.core.DiffHelp;
|
||||
import io.ebeaninternal.server.core.Message;
|
||||
import io.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.lib.util.Str;
|
||||
@@ -18,6 +21,7 @@ import io.ebeaninternal.server.transaction.TransactionManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -45,7 +49,10 @@ public class CQueryEngine {
|
||||
|
||||
private final CQueryHistorySupport historySupport;
|
||||
|
||||
private final DatabasePlatform dbPlatform;
|
||||
|
||||
public CQueryEngine(ServerConfig serverConfig, DatabasePlatform dbPlatform, Binder binder, Map<String, String> asOfTableMapping, Map<String, String> draftTableMap) {
|
||||
this.dbPlatform = dbPlatform;
|
||||
this.defaultFetchSizeFindEach = serverConfig.getJdbcFetchSizeFindEach();
|
||||
this.defaultFetchSizeFindList = serverConfig.getJdbcFetchSizeFindList();
|
||||
this.forwardOnlyHintOnFindIterate = dbPlatform.isForwardOnlyHintOnFindIterate();
|
||||
@@ -83,7 +90,7 @@ public class CQueryEngine {
|
||||
return rows;
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw CQuery.createPersistenceException(e, request.getTransaction(), query.getBindLog(), query.getGeneratedSql());
|
||||
throw translate(request, query.getBindLog(), query.getGeneratedSql(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,10 +116,30 @@ public class CQueryEngine {
|
||||
return list;
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw CQuery.createPersistenceException(e, request.getTransaction(), rcQuery.getBindLog(), rcQuery.getGeneratedSql());
|
||||
throw translate(request, rcQuery.getBindLog(), rcQuery.getGeneratedSql(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the SQLException into a PersistenceException.
|
||||
*/
|
||||
<T> PersistenceException translate(OrmQueryRequest<T> request, String bindLog, String sql, SQLException e) {
|
||||
SpiTransaction t = request.getTransaction();
|
||||
if (t.isLogSummary()) {
|
||||
// log the error to the transaction log
|
||||
String errMsg = StringHelper.replaceStringMulti(e.getMessage(), new String[]{"\r", "\n"}, "\\n ");
|
||||
String msg = "ERROR executing query, bindLog[" + bindLog + "] error[" + errMsg + "]";
|
||||
t.logSummary(msg);
|
||||
}
|
||||
|
||||
// ensure 'rollback' is logged if queryOnly transaction
|
||||
t.getConnection();
|
||||
|
||||
// build a decent error message for the exception
|
||||
String m = Message.msg("fetch.sqlerror", e.getMessage(), bindLog, sql);
|
||||
return dbPlatform.translate(m, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and execute the find Id's query.
|
||||
*/
|
||||
@@ -155,7 +182,7 @@ public class CQueryEngine {
|
||||
return count;
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw CQuery.createPersistenceException(e, request.getTransaction(), rcQuery.getBindLog(), rcQuery.getGeneratedSql());
|
||||
throw translate(request, rcQuery.getBindLog(), rcQuery.getGeneratedSql(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ import io.ebeaninternal.server.core.OrmQueryEngine;
|
||||
import io.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@@ -28,10 +30,14 @@ public class DefaultOrmQueryEngine implements OrmQueryEngine {
|
||||
* Create the Finder.
|
||||
*/
|
||||
public DefaultOrmQueryEngine(CQueryEngine queryEngine) {
|
||||
|
||||
this.queryEngine = queryEngine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> PersistenceException translate(OrmQueryRequest<T> request, String bindLog, String sql, SQLException e) {
|
||||
return queryEngine.translate(request, bindLog, sql, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the jdbc batch by default unless explicitly turned off on the transaction.
|
||||
*/
|
||||
|
||||
@@ -206,9 +206,9 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
private Boolean autoTune;
|
||||
|
||||
/**
|
||||
* Allow to fetch a record "for update" which should lock it on read
|
||||
* For update mode.
|
||||
*/
|
||||
private boolean forUpdate;
|
||||
private ForUpdate forUpdate;
|
||||
|
||||
private boolean singleAttribute;
|
||||
|
||||
@@ -579,7 +579,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
// includes joins and we use - delete ... where id in (...)
|
||||
maxRows = 0;
|
||||
firstRow = 0;
|
||||
forUpdate = false;
|
||||
forUpdate = null;
|
||||
rootTableAlias = "${RTA}"; // alias we remove later
|
||||
setSelectId();
|
||||
}
|
||||
@@ -791,11 +791,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return autoTune;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForUpdate() {
|
||||
return forUpdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultRawSqlIfRequired() {
|
||||
if (beanDescriptor.isRawSqlBased() && rawSql == null) {
|
||||
@@ -811,11 +806,42 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> setForUpdate(boolean forUpdate) {
|
||||
this.forUpdate = forUpdate;
|
||||
this.forUpdate = (forUpdate) ? ForUpdate.BASE : null;
|
||||
this.excludeBeanCache = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> forUpdate() {
|
||||
return setForUpdateWithMode(ForUpdate.BASE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> forUpdateNoWait() {
|
||||
return setForUpdateWithMode(ForUpdate.NOWAIT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> forUpdateSkipLocked() {
|
||||
return setForUpdateWithMode(ForUpdate.SKIPLOCKED);
|
||||
}
|
||||
|
||||
private DefaultOrmQuery<T> setForUpdateWithMode(ForUpdate mode) {
|
||||
this.forUpdate = mode;
|
||||
this.excludeBeanCache = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForUpdate() {
|
||||
return forUpdate != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ForUpdate getForUpdateMode() {
|
||||
return forUpdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfilingListener getProfilingListener() {
|
||||
return profilingListener;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.querydefn;
|
||||
|
||||
import io.ebean.OrderBy;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.RawSql;
|
||||
import io.ebeaninternal.api.BindParams;
|
||||
import io.ebeaninternal.api.CQueryPlanKey;
|
||||
@@ -14,61 +15,69 @@ import io.ebeaninternal.server.deploy.TableJoin;
|
||||
*/
|
||||
class OrmQueryPlanKey implements CQueryPlanKey {
|
||||
|
||||
private final String m2mIncludeTable;
|
||||
private final String orderByAsSting;
|
||||
private final SpiExpression where;
|
||||
private final SpiExpression having;
|
||||
private final RawSql.Key rawSqlKey;
|
||||
private final boolean hasIdValue;
|
||||
private final SpiQuery.Type type;
|
||||
private final int maxRows;
|
||||
private final int firstRow;
|
||||
private final boolean disableLazyLoading;
|
||||
private final boolean distinct;
|
||||
private final boolean sqlDistinct;
|
||||
private final String mapKey;
|
||||
private final SpiQuery.TemporalMode temporalMode;
|
||||
private final boolean forUpdate;
|
||||
private final String rootTableAlias;
|
||||
private final OrmUpdateProperties updateProperties;
|
||||
|
||||
private final int planHash;
|
||||
private final int bindCount;
|
||||
private final String options;
|
||||
|
||||
OrmQueryPlanKey(TableJoin m2mIncludeTable, SpiQuery.Type type, OrmQueryDetail detail, int maxRows, int firstRow, boolean disableLazyLoading, OrderBy<?> orderBy, boolean distinct, boolean sqlDistinct, String mapKey, Object id, BindParams bindParams, SpiExpression whereExpressions, SpiExpression havingExpressions, SpiQuery.TemporalMode temporalMode, boolean forUpdate, String rootTableAlias, RawSql rawSql, OrmUpdateProperties updateProperties) {
|
||||
OrmQueryPlanKey(TableJoin m2mIncludeTable, SpiQuery.Type type, OrmQueryDetail detail, int maxRows, int firstRow, boolean disableLazyLoading,
|
||||
OrderBy<?> orderBy, boolean distinct, boolean sqlDistinct, String mapKey, Object id, BindParams bindParams,
|
||||
SpiExpression whereExpressions, SpiExpression havingExpressions, SpiQuery.TemporalMode temporalMode,
|
||||
Query.ForUpdate forUpdate, String rootTableAlias, RawSql rawSql, OrmUpdateProperties updateProperties) {
|
||||
|
||||
this.m2mIncludeTable = m2mIncludeTable == null ? null : m2mIncludeTable.getTable();
|
||||
this.type = type;
|
||||
StringBuilder sb = new StringBuilder(300);
|
||||
if (type != null) {
|
||||
sb.append("t:").append(type.ordinal());
|
||||
}
|
||||
if (temporalMode != SpiQuery.TemporalMode.CURRENT) {
|
||||
sb.append(",temp:").append(temporalMode.ordinal());
|
||||
}
|
||||
if (forUpdate != null) {
|
||||
sb.append(",forUpd:").append(forUpdate.ordinal());
|
||||
}
|
||||
if (id != null) {
|
||||
sb.append(",id:");
|
||||
}
|
||||
if (distinct) {
|
||||
sb.append(",dist:");
|
||||
}
|
||||
if (sqlDistinct) {
|
||||
sb.append(",sqlD:");
|
||||
}
|
||||
if (disableLazyLoading) {
|
||||
sb.append(",disLazy:");
|
||||
}
|
||||
if (rootTableAlias != null) {
|
||||
sb.append(",root:").append(rootTableAlias);
|
||||
}
|
||||
if (orderBy != null) {
|
||||
sb.append(",orderBy:").append(orderBy.toStringFormat());
|
||||
}
|
||||
if (m2mIncludeTable != null) {
|
||||
sb.append(",m2m:").append(m2mIncludeTable.getTable());
|
||||
}
|
||||
if (mapKey != null) {
|
||||
sb.append(",mapKey:").append(mapKey);
|
||||
}
|
||||
this.options = sb.toString();
|
||||
this.maxRows = maxRows;
|
||||
this.firstRow = firstRow;
|
||||
this.disableLazyLoading = disableLazyLoading;
|
||||
this.orderByAsSting = (orderBy == null) ? null : orderBy.toStringFormat();
|
||||
this.distinct = distinct;
|
||||
this.sqlDistinct = sqlDistinct;
|
||||
this.mapKey = mapKey;
|
||||
this.hasIdValue = (id != null);
|
||||
this.where = (whereExpressions == null) ? null : whereExpressions.copyForPlanKey();
|
||||
this.having = (havingExpressions == null) ? null : havingExpressions.copyForPlanKey();
|
||||
this.temporalMode = temporalMode;
|
||||
this.forUpdate = forUpdate;
|
||||
this.rootTableAlias = rootTableAlias;
|
||||
this.updateProperties = updateProperties;
|
||||
this.rawSqlKey = (rawSql == null) ? null : rawSql.getKey();
|
||||
|
||||
// exclude bind values and things unrelated to the sql being generated
|
||||
HashQueryPlanBuilder builder = new HashQueryPlanBuilder();
|
||||
|
||||
builder.add((type == null ? 0 : type.ordinal() + 1));
|
||||
builder.add(distinct).add(sqlDistinct);
|
||||
builder.add(options.hashCode());
|
||||
builder.add(firstRow).add(maxRows);
|
||||
builder.add(orderBy).add(forUpdate);
|
||||
builder.add(mapKey);
|
||||
builder.add(disableLazyLoading);
|
||||
builder.add(hasIdValue);
|
||||
builder.add(temporalMode);
|
||||
builder.add(rawSqlKey == null ? 0 : rawSqlKey.hashCode());
|
||||
builder.add(this.m2mIncludeTable);
|
||||
builder.add(rootTableAlias);
|
||||
|
||||
if (detail != null) {
|
||||
detail.queryPlanHash(builder);
|
||||
@@ -111,23 +120,10 @@ class OrmQueryPlanKey implements CQueryPlanKey {
|
||||
if (bindCount != that.bindCount) return false;
|
||||
if (maxRows != that.maxRows) return false;
|
||||
if (firstRow != that.firstRow) return false;
|
||||
if (disableLazyLoading != that.disableLazyLoading) return false;
|
||||
if (distinct != that.distinct) return false;
|
||||
if (sqlDistinct != that.sqlDistinct) return false;
|
||||
if (forUpdate != that.forUpdate) return false;
|
||||
if (hasIdValue != that.hasIdValue) return false;
|
||||
if (type != that.type) return false;
|
||||
if (temporalMode != that.temporalMode) return false;
|
||||
if (m2mIncludeTable != null ? !m2mIncludeTable.equals(that.m2mIncludeTable) : that.m2mIncludeTable != null)
|
||||
return false;
|
||||
if (orderByAsSting != null ? !orderByAsSting.equals(that.orderByAsSting) : that.orderByAsSting != null)
|
||||
return false;
|
||||
if (!options.equals(that.options)) return false;
|
||||
if (where != null ? !where.isSameByPlan(that.where) : that.where != null) return false;
|
||||
if (having != null ? !having.isSameByPlan(that.having) : that.having != null) return false;
|
||||
if (updateProperties != null ? !updateProperties.isSameByPlan(that.updateProperties) : that.updateProperties != null)
|
||||
return false;
|
||||
if (rawSqlKey != null ? !rawSqlKey.equals(that.rawSqlKey) : that.rawSqlKey != null) return false;
|
||||
if (mapKey != null ? !mapKey.equals(that.mapKey) : that.mapKey != null) return false;
|
||||
return rootTableAlias != null ? rootTableAlias.equals(that.rootTableAlias) : that.rootTableAlias == null;
|
||||
if (updateProperties != null ? !updateProperties.isSameByPlan(that.updateProperties) : that.updateProperties != null) return false;
|
||||
return rawSqlKey != null ? rawSqlKey.equals(that.rawSqlKey) : that.rawSqlKey == null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package io.ebeaninternal.server.transaction;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.RollbackException;
|
||||
import java.sql.Connection;
|
||||
|
||||
/**
|
||||
@@ -43,7 +42,7 @@ public class ExternalJdbcTransaction extends JdbcTransaction {
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public void commit() throws RollbackException {
|
||||
public void commit() {
|
||||
throw new PersistenceException("This is an external transaction so must be committed externally");
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import io.ebeaninternal.server.core.PersistRequest;
|
||||
import io.ebeaninternal.server.core.PersistRequestBean;
|
||||
import io.ebeaninternal.server.lib.util.Str;
|
||||
import io.ebeaninternal.server.persist.BatchControl;
|
||||
import io.ebeaninternal.server.persist.BatchedSqlException;
|
||||
import io.ebeanservice.docstore.api.DocStoreTransaction;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -620,28 +621,45 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
@Override
|
||||
public void flushBatchOnCollection() {
|
||||
if (batchOnCascadeSet) {
|
||||
if (batchControl != null) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("... flushBatchOnCollection");
|
||||
}
|
||||
batchControl.flushReset();
|
||||
}
|
||||
batchFlushReset();
|
||||
// restore the previous batch mode of NONE
|
||||
batchMode = PersistBatch.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
private void batchFlush() {
|
||||
if (batchControl != null) {
|
||||
try {
|
||||
batchControl.flush();
|
||||
} catch (BatchedSqlException e) {
|
||||
throw translate(e.getMessage(), e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void batchFlushReset() {
|
||||
if (batchControl != null) {
|
||||
try {
|
||||
batchControl.flushReset();
|
||||
} catch (BatchedSqlException e) {
|
||||
throw translate(e.getMessage(), e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PersistenceException translate(String message, SQLException cause) {
|
||||
if (manager != null) {
|
||||
return manager.translate(message, cause);
|
||||
}
|
||||
return new PersistenceException(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush after completing persist cascade.
|
||||
*/
|
||||
@Override
|
||||
public void flushBatchOnCascade() {
|
||||
if (batchControl != null) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("... flushBatchOnCascade");
|
||||
}
|
||||
batchControl.flushReset();
|
||||
}
|
||||
batchFlushReset();
|
||||
// restore the previous batch mode
|
||||
batchMode = oldBatchMode;
|
||||
}
|
||||
@@ -670,21 +688,13 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
// escalate up to batch mode for this request (and cascade)
|
||||
oldBatchMode = batchMode;
|
||||
batchMode = PersistBatch.ALL;
|
||||
if (batchControl != null) {
|
||||
// flush with reset so that this request goes into it's own batch buffer
|
||||
batchControl.flushReset();
|
||||
}
|
||||
batchFlushReset();
|
||||
// skip using jdbc batch for the top level bean (no gain there)
|
||||
request.setSkipBatchForTopLevel();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (batchControl != null && !batchControl.isEmpty()) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("... flush from batchOnCascade ");
|
||||
}
|
||||
batchControl.flushReset();
|
||||
}
|
||||
batchFlushReset();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -732,9 +742,7 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
* Flush the JDBC batch and execute derived relationship statements if necessary.
|
||||
*/
|
||||
private void internalBatchFlush() {
|
||||
if (batchControl != null) {
|
||||
batchControl.flush();
|
||||
}
|
||||
batchFlush();
|
||||
if (deferredList != null) {
|
||||
for (PersistDeferredRelationship deferred : deferredList) {
|
||||
deferred.execute(this);
|
||||
@@ -935,7 +943,7 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public void commitAndContinue() throws RollbackException {
|
||||
public void commitAndContinue() {
|
||||
if (rollbackOnly) {
|
||||
return;
|
||||
}
|
||||
@@ -951,7 +959,7 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
|
||||
} catch (Exception e) {
|
||||
doRollback(e);
|
||||
throw new RollbackException(e);
|
||||
throw wrapIfNeeded(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -959,7 +967,7 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
* Commit the transaction.
|
||||
*/
|
||||
@Override
|
||||
public void commit() throws RollbackException {
|
||||
public void commit() {
|
||||
if (rollbackOnly) {
|
||||
rollback();
|
||||
return;
|
||||
@@ -976,13 +984,24 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
|
||||
} catch (Exception e) {
|
||||
doRollback(e);
|
||||
throw new RollbackException(e);
|
||||
throw wrapIfNeeded(e);
|
||||
|
||||
} finally {
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to keep specific exceptions and otherwise wrap as RollbackException.
|
||||
*/
|
||||
private RuntimeException wrapIfNeeded(Exception e) {
|
||||
if (e instanceof PersistenceException) {
|
||||
// keep more specific exception if we have it
|
||||
return (PersistenceException)e;
|
||||
}
|
||||
return new RollbackException(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the transaction manager.
|
||||
*/
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.transaction;
|
||||
import io.ebean.BackgroundExecutor;
|
||||
import io.ebean.config.CurrentTenantProvider;
|
||||
import io.ebean.PersistBatch;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform.OnQueryOnly;
|
||||
import io.ebean.event.changelog.ChangeLogListener;
|
||||
import io.ebean.event.changelog.ChangeLogPrepare;
|
||||
@@ -19,8 +20,10 @@ import io.ebeanservice.docstore.api.DocStoreUpdates;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -100,11 +103,14 @@ public class TransactionManager {
|
||||
|
||||
private final TransactionFactory transactionFactory;
|
||||
|
||||
private final DatabasePlatform databasePlatform;
|
||||
|
||||
/**
|
||||
* Create the TransactionManager
|
||||
*/
|
||||
public TransactionManager(TransactionManagerOptions options) {
|
||||
|
||||
this.databasePlatform = options.config.getDatabasePlatform();
|
||||
this.skipCacheAfterWrite = options.config.isSkipCacheAfterWrite();
|
||||
this.localL2Caching = options.localL2Caching;
|
||||
this.persistBatch = options.config.getPersistBatch();
|
||||
@@ -132,6 +138,13 @@ public class TransactionManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the SQLException into a specific exception if possible based on the DB platform.
|
||||
*/
|
||||
public PersistenceException translate(String message, SQLException cause) {
|
||||
return databasePlatform.translate(message, cause);
|
||||
}
|
||||
|
||||
public void shutdown(boolean shutdownDataSource, boolean deregisterDriver) {
|
||||
if (shutdownDataSource) {
|
||||
dataSourceSupplier.shutdown(deregisterDriver);
|
||||
|
||||
Reference in New Issue
Block a user