From a08cf548e77e4d1ad0f63bf4a6287ac059811f5b Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Sun, 21 Jul 2019 22:57:56 +1200 Subject: [PATCH] #1770 - Support use of Savepoints with MySql and MariaDB (that barf on savepoint.getSavepointId()) --- .../config/dbplatform/DatabasePlatform.java | 9 ++++++ .../dbplatform/mysql/MySqlPlatform.java | 1 + .../AutoCommitTransactionManager.java | 5 ++- .../DocStoreTransactionManager.java | 10 ++---- .../ExplicitTransactionManager.java | 5 ++- .../transaction/SavepointTransaction.java | 8 +++-- .../transaction/TransactionFactory.java | 3 -- .../transaction/TransactionFactoryBasic.java | 2 +- .../transaction/TransactionFactoryTenant.java | 2 +- .../transaction/TransactionManager.java | 31 +++++++++++++++++-- 10 files changed, 54 insertions(+), 22 deletions(-) diff --git a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java index 6a96724e8..445ec3d15 100644 --- a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java @@ -51,6 +51,8 @@ public class DatabasePlatform { protected boolean supportsDeleteTableAlias; + protected boolean supportsSavepointId = true; + /** * The behaviour used when ending a read only transaction at read committed isolation level. */ @@ -328,6 +330,13 @@ public class DatabasePlatform { return caseSensitiveCollation; } + /** + * Return true if the platform supports SavepointId values. + */ + public boolean isSupportsSavepointId() { + return supportsSavepointId; + } + /** * Return the maximum table name length. *

diff --git a/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java b/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java index e9c769095..e744ecbad 100644 --- a/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java @@ -27,6 +27,7 @@ public class MySqlPlatform extends DatabasePlatform { this.platform = Platform.MYSQL; this.useExtraTransactionOnIterateSecondaryQueries = true; this.selectCountWithAlias = true; + this.supportsSavepointId = false; this.dbEncrypt = new MySqlDbEncrypt(); this.historySupport = new MySqlHistorySupport(); this.columnAliasPrefix = null; diff --git a/src/main/java/io/ebeaninternal/server/transaction/AutoCommitTransactionManager.java b/src/main/java/io/ebeaninternal/server/transaction/AutoCommitTransactionManager.java index ca862ebfa..29fb720c0 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/AutoCommitTransactionManager.java +++ b/src/main/java/io/ebeaninternal/server/transaction/AutoCommitTransactionManager.java @@ -19,9 +19,8 @@ public class AutoCommitTransactionManager extends TransactionManager { * Create an autoCommit based Transaction. */ @Override - protected SpiTransaction createTransaction(boolean explicit, Connection c, long id) { - - return new AutoCommitJdbcTransaction(prefix + id, explicit, c, this); + protected SpiTransaction createTransaction(boolean explicit, Connection c) { + return new AutoCommitJdbcTransaction(nextTxnId(), explicit, c, this); } } diff --git a/src/main/java/io/ebeaninternal/server/transaction/DocStoreTransactionManager.java b/src/main/java/io/ebeaninternal/server/transaction/DocStoreTransactionManager.java index 53f1f5c04..a4f8a0eff 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/DocStoreTransactionManager.java +++ b/src/main/java/io/ebeaninternal/server/transaction/DocStoreTransactionManager.java @@ -3,7 +3,6 @@ package io.ebeaninternal.server.transaction; import io.ebeaninternal.api.SpiTransaction; import java.sql.Connection; -import java.util.concurrent.atomic.AtomicLong; /** * Transaction manager used for doc store only EbeanServer instance. @@ -12,8 +11,6 @@ import java.util.concurrent.atomic.AtomicLong; */ public class DocStoreTransactionManager extends TransactionManager { - private final AtomicLong counter = new AtomicLong(1000L); - /** * Create the TransactionManager */ @@ -23,8 +20,7 @@ public class DocStoreTransactionManager extends TransactionManager { @Override public SpiTransaction createTransaction(boolean explicit, int isolationLevel) { - long id = counter.incrementAndGet(); - return createTransaction(explicit, null, id); + return createTransaction(explicit, null); } @Override @@ -33,7 +29,7 @@ public class DocStoreTransactionManager extends TransactionManager { } @Override - protected SpiTransaction createTransaction(boolean explicit, Connection c, long id) { - return new DocStoreOnlyTransaction(prefix + id, explicit, this); + protected SpiTransaction createTransaction(boolean explicit, Connection c) { + return new DocStoreOnlyTransaction(nextTxnId(), explicit, this); } } diff --git a/src/main/java/io/ebeaninternal/server/transaction/ExplicitTransactionManager.java b/src/main/java/io/ebeaninternal/server/transaction/ExplicitTransactionManager.java index 8d082c3e3..a9640cb10 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/ExplicitTransactionManager.java +++ b/src/main/java/io/ebeaninternal/server/transaction/ExplicitTransactionManager.java @@ -18,9 +18,8 @@ public class ExplicitTransactionManager extends TransactionManager { * Create a ExplicitJdbcTransaction. */ @Override - protected SpiTransaction createTransaction(boolean explicit, Connection c, long id) { - - return new ExplicitJdbcTransaction(prefix + id, explicit, c, this); + protected SpiTransaction createTransaction(boolean explicit, Connection c) { + return new ExplicitJdbcTransaction(nextTxnId(), explicit, c, this); } /** diff --git a/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java b/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java index 271cb1144..b50122f5c 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java +++ b/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java @@ -31,8 +31,12 @@ class SavepointTransaction extends SpiTransactionProxy { this.transaction = transaction; this.connection = transaction.getInternalConnection(); this.savepoint = connection.setSavepoint(); - int savepointId = savepoint.getSavepointId(); - this.spPrefix = "sp[" + savepointId + "] "; + if (manager.isTxnDebug()) { + int savepointId = manager.isSupportsSavepointId() ? savepoint.getSavepointId() : 0; + this.spPrefix = "sp[" + savepointId + "] "; + } else { + this.spPrefix = "sp[] "; + } this.logPrefix = transaction.getLogPrefix() + spPrefix; } diff --git a/src/main/java/io/ebeaninternal/server/transaction/TransactionFactory.java b/src/main/java/io/ebeaninternal/server/transaction/TransactionFactory.java index fedcd5f3a..3d45ad3eb 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/TransactionFactory.java +++ b/src/main/java/io/ebeaninternal/server/transaction/TransactionFactory.java @@ -6,15 +6,12 @@ import io.ebeaninternal.api.SpiTransaction; import javax.persistence.PersistenceException; import java.sql.Connection; import java.sql.SQLException; -import java.util.concurrent.atomic.AtomicLong; /** * Creates transactions with implementations for basic mode and multi-tenancy mode. */ abstract class TransactionFactory { - final AtomicLong counter = new AtomicLong(1000); - final TransactionManager manager; TransactionFactory(TransactionManager manager) { diff --git a/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryBasic.java b/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryBasic.java index 88959e921..a175f762a 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryBasic.java +++ b/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryBasic.java @@ -52,7 +52,7 @@ class TransactionFactoryBasic extends TransactionFactory { } private SpiTransaction create(boolean explicit, Connection c) { - return manager.createTransaction(explicit, c, counter.incrementAndGet()); + return manager.createTransaction(explicit, c); } } diff --git a/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryTenant.java b/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryTenant.java index fdb76e23e..63515c13f 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryTenant.java +++ b/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryTenant.java @@ -43,7 +43,7 @@ class TransactionFactoryTenant extends TransactionFactory { tenantId = tenantProvider.currentId(); } connection = dataSourceSupplier.getConnection(tenantId); - SpiTransaction transaction = manager.createTransaction(explicit, connection, counter.incrementAndGet()); + SpiTransaction transaction = manager.createTransaction(explicit, connection); transaction.setTenantId(tenantId); return transaction; diff --git a/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java b/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java index 396159846..46e0fb2fd 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java +++ b/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java @@ -45,6 +45,7 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.List; import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; /** * Manages transactions. @@ -73,6 +74,8 @@ public class TransactionManager implements SpiTransactionManager { private final String externalTransPrefix; + private final AtomicLong counter = new AtomicLong(1000L); + /** * The dataSource of connections. */ @@ -129,6 +132,7 @@ public class TransactionManager implements SpiTransactionManager { private final SpiLogManager logManager; private final SpiLogger txnLogger; + private final boolean txnDebug; private final DatabasePlatform databasePlatform; @@ -141,6 +145,7 @@ public class TransactionManager implements SpiTransactionManager { private final TableModState tableModState; private final ServerCacheNotify cacheNotify; + private final boolean supportsSavepointId; /** * Create the TransactionManager @@ -149,7 +154,9 @@ public class TransactionManager implements SpiTransactionManager { this.logManager = options.logManager; this.txnLogger = logManager.txn(); + this.txnDebug = txnLogger.isDebug(); this.databasePlatform = options.config.getDatabasePlatform(); + this.supportsSavepointId = databasePlatform.isSupportsSavepointId(); this.skipCacheAfterWrite = options.config.isSkipCacheAfterWrite(); this.notifyL2CacheInForeground = options.notifyL2CacheInForeground; this.persistBatch = PersistBatch.ALL == options.config.getPersistBatch(); @@ -242,6 +249,13 @@ public class TransactionManager implements SpiTransactionManager { } } + /** + * Return true if the DB platform supports SavepointId(). + */ + boolean isSupportsSavepointId() { + return supportsSavepointId; + } + boolean isDocStoreActive() { return docStoreActive; } @@ -352,9 +366,15 @@ public class TransactionManager implements SpiTransactionManager { /** * Create a new transaction. */ - SpiTransaction createTransaction(boolean explicit, Connection c, long id) { + SpiTransaction createTransaction(boolean explicit, Connection c) { + return new JdbcTransaction(nextTxnId(), explicit, c, this); + } - return new JdbcTransaction(prefix + id, explicit, c, this); + /** + * Return the next transaction id. + */ + String nextTxnId() { + return txnDebug ? prefix + counter.incrementAndGet() : prefix; } /** @@ -728,6 +748,13 @@ public class TransactionManager implements SpiTransactionManager { } } + /** + * Return true if Transaction debug is on. + */ + public boolean isTxnDebug() { + return txnDebug; + } + public SpiLogManager log() { return logManager; }