mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Refactor DefaultTransactionThreadLocal, convert ThreadLocal to field (from map) (#1716)
* Refactor DefaultTransactionThreadLocal, convert ThreadLocal to field (from map) * Add test for multiple database thread locals
This commit is contained in:
@@ -15,8 +15,7 @@ import io.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.expression.platform.DbExpressionHandler;
|
||||
import io.ebeaninternal.server.expression.platform.DbExpressionHandlerFactory;
|
||||
import io.ebeaninternal.server.transaction.DefaultTransactionThreadLocal;
|
||||
|
||||
import io.ebeaninternal.server.transaction.TransactionScopeManager;
|
||||
import org.avaje.agentloader.AgentLoader;
|
||||
import org.junit.After;
|
||||
import org.junit.Rule;
|
||||
@@ -28,7 +27,6 @@ import org.tests.model.basic.Country;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -43,13 +41,12 @@ public abstract class BaseTestCase {
|
||||
|
||||
@After
|
||||
public void checkForLeak() {
|
||||
Map<String, SpiTransaction> trans = DefaultTransactionThreadLocal.currentTransactions();
|
||||
TransactionScopeManager scope = spiEbeanServer().getTransactionManager().scope();
|
||||
SpiTransaction trans = scope.getInScope();
|
||||
if (trans != null) {
|
||||
if (!trans.isEmpty()) {
|
||||
String msg = getClass().getSimpleName() + "." + name.getMethodName() + " did not clear threadScope:" + trans;
|
||||
trans.clear(); // clear for next test
|
||||
fail(msg);
|
||||
}
|
||||
String msg = getClass().getSimpleName() + "." + name.getMethodName() + " did not clear threadScope:" + trans;
|
||||
scope.clearExternal(); // clear for next test
|
||||
fail(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +101,10 @@ public abstract class BaseTestCase {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
protected SpiTransaction getInScopeTransaction() {
|
||||
return spiEbeanServer().getTransactionManager().scope().getInScope();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the generated sql trimming column alias if required.
|
||||
*/
|
||||
|
||||
+53
-10
@@ -1,13 +1,21 @@
|
||||
package io.ebeaninternal.server.transaction;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.annotation.ForPlatform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.EBasicVer;
|
||||
import org.tests.model.basic.UTDetail;
|
||||
import org.tests.model.basic.UTMaster;
|
||||
|
||||
import static org.assertj.core.api.StrictAssertions.assertThat;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
@@ -18,12 +26,12 @@ public class DefaultTransactionThreadLocalTest extends BaseTestCase {
|
||||
@Test
|
||||
public void get() {
|
||||
Ebean.execute(() -> {
|
||||
SpiTransaction txn = DefaultTransactionThreadLocal.get("h2");
|
||||
SpiTransaction txn = getInScopeTransaction();
|
||||
assertNotNull(txn);
|
||||
});
|
||||
|
||||
// thread local should be set to null
|
||||
assertNull(DefaultTransactionThreadLocal.get("h2"));
|
||||
assertNull(getInScopeTransaction());
|
||||
}
|
||||
|
||||
@ForPlatform({Platform.H2})
|
||||
@@ -32,19 +40,19 @@ public class DefaultTransactionThreadLocalTest extends BaseTestCase {
|
||||
|
||||
try (Transaction transaction = Ebean.beginTransaction()) {
|
||||
assertNotNull(transaction);
|
||||
SpiTransaction txn = DefaultTransactionThreadLocal.get("h2");
|
||||
SpiTransaction txn = getInScopeTransaction();
|
||||
assertSame(txn, transaction);
|
||||
|
||||
try (Transaction nested = Ebean.beginTransaction()) {
|
||||
assertNotNull(nested);
|
||||
SpiTransaction txnNested = DefaultTransactionThreadLocal.get("h2");
|
||||
SpiTransaction txnNested = getInScopeTransaction();
|
||||
assertSame(txnNested, nested);
|
||||
}
|
||||
|
||||
assertNotNull(DefaultTransactionThreadLocal.get("h2"));
|
||||
assertNotNull(getInScopeTransaction());
|
||||
}
|
||||
|
||||
assertNull(DefaultTransactionThreadLocal.get("h2"));
|
||||
assertNull(getInScopeTransaction());
|
||||
}
|
||||
|
||||
@ForPlatform({Platform.H2})
|
||||
@@ -53,9 +61,9 @@ public class DefaultTransactionThreadLocalTest extends BaseTestCase {
|
||||
|
||||
try (Transaction transaction = Ebean.beginTransaction()) {
|
||||
transaction.commit();
|
||||
assertNull(DefaultTransactionThreadLocal.get("h2"));
|
||||
assertNull(getInScopeTransaction());
|
||||
}
|
||||
assertNull(DefaultTransactionThreadLocal.get("h2"));
|
||||
assertNull(getInScopeTransaction());
|
||||
}
|
||||
|
||||
@ForPlatform({Platform.H2})
|
||||
@@ -65,9 +73,9 @@ public class DefaultTransactionThreadLocalTest extends BaseTestCase {
|
||||
try (Transaction transaction = Ebean.beginTransaction()) {
|
||||
|
||||
transaction.rollback();
|
||||
assertNull(DefaultTransactionThreadLocal.get("h2"));
|
||||
assertNull(getInScopeTransaction());
|
||||
}
|
||||
assertNull(DefaultTransactionThreadLocal.get("h2"));
|
||||
assertNull(getInScopeTransaction());
|
||||
}
|
||||
|
||||
@ForPlatform({Platform.H2})
|
||||
@@ -78,4 +86,39 @@ public class DefaultTransactionThreadLocalTest extends BaseTestCase {
|
||||
Ebean.endTransaction();
|
||||
}
|
||||
|
||||
@ForPlatform({Platform.H2})
|
||||
@Test
|
||||
public void multi_database_threadlocals() {
|
||||
|
||||
Database db = DB.getDefault();
|
||||
Database otherDb = createOtherDatabase();
|
||||
try {
|
||||
try (Transaction dbTxn = db.beginTransaction()) {
|
||||
try (Transaction otherDbTxn = otherDb.beginTransaction()) {
|
||||
assertThat(dbTxn).isNotSameAs(otherDbTxn);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
otherDb.shutdown(true, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Database createOtherDatabase() {
|
||||
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
config.setName("h2ebasicver");
|
||||
config.loadFromProperties();
|
||||
config.setDdlGenerate(true);
|
||||
config.setDdlRun(true);
|
||||
config.setDdlExtra(false);
|
||||
|
||||
config.setRegister(false);
|
||||
config.setDefaultServer(false);
|
||||
config.getClasses().add(EBasicVer.class);
|
||||
config.getClasses().add(UTMaster.class);
|
||||
config.getClasses().add(UTDetail.class);
|
||||
|
||||
return DatabaseFactory.create(config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.annotation.Transactional;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
import io.ebeaninternal.server.transaction.DefaultTransactionThreadLocal;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.tests.model.basic.Order;
|
||||
@@ -37,8 +36,7 @@ public class TestExecuteComplete extends BaseTestCase {
|
||||
fail();
|
||||
} catch (DataIntegrityException e) {
|
||||
// assert the thread local has been cleaned up
|
||||
SpiTransaction txn = DefaultTransactionThreadLocal.get("h2");
|
||||
assertThat(txn).isNull();
|
||||
assertThat(getInScopeTransaction()).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,8 +57,7 @@ public class TestExecuteComplete extends BaseTestCase {
|
||||
fail();
|
||||
} catch (DataIntegrityException e) {
|
||||
// assert the thread local has been cleaned up
|
||||
SpiTransaction txn = DefaultTransactionThreadLocal.get("h2");
|
||||
assertThat(txn).isNull();
|
||||
assertThat(getInScopeTransaction()).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,8 +69,7 @@ public class TestExecuteComplete extends BaseTestCase {
|
||||
errorOnCommit();
|
||||
fail();
|
||||
} catch (DataIntegrityException e) {
|
||||
SpiTransaction txn = DefaultTransactionThreadLocal.get("h2");
|
||||
assertThat(txn).isNull();
|
||||
assertThat(getInScopeTransaction()).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,8 +93,7 @@ public class TestExecuteComplete extends BaseTestCase {
|
||||
txn1.end();
|
||||
}
|
||||
|
||||
SpiTransaction txn2 = DefaultTransactionThreadLocal.get("h2");
|
||||
assertThat(txn2).isNull();
|
||||
assertThat(getInScopeTransaction()).isNull();
|
||||
}
|
||||
|
||||
@ForPlatform(Platform.H2)
|
||||
@@ -113,8 +108,7 @@ public class TestExecuteComplete extends BaseTestCase {
|
||||
//txn1.end();
|
||||
}
|
||||
|
||||
SpiTransaction txn2 = DefaultTransactionThreadLocal.get("h2");
|
||||
assertThat(txn2).isNull();
|
||||
assertThat(getInScopeTransaction()).isNull();
|
||||
}
|
||||
|
||||
@ForPlatform(Platform.H2)
|
||||
@@ -129,8 +123,7 @@ public class TestExecuteComplete extends BaseTestCase {
|
||||
//txn1.end();
|
||||
}
|
||||
|
||||
SpiTransaction txn2 = DefaultTransactionThreadLocal.get("h2");
|
||||
assertThat(txn2).isNull();
|
||||
assertThat(getInScopeTransaction()).isNull();
|
||||
}
|
||||
|
||||
@ForPlatform(Platform.H2)
|
||||
@@ -139,8 +132,7 @@ public class TestExecuteComplete extends BaseTestCase {
|
||||
|
||||
DB.find(Customer.class).findList();
|
||||
|
||||
SpiTransaction txn = DefaultTransactionThreadLocal.get("h2");
|
||||
assertThat(txn).isNull();
|
||||
assertThat(getInScopeTransaction()).isNull();
|
||||
}
|
||||
|
||||
@ForPlatform(Platform.H2)
|
||||
@@ -151,8 +143,7 @@ public class TestExecuteComplete extends BaseTestCase {
|
||||
cust.setName("Roland");
|
||||
DB.save(cust);
|
||||
|
||||
SpiTransaction txn = DefaultTransactionThreadLocal.get("h2");
|
||||
assertThat(txn).isNull();
|
||||
assertThat(getInScopeTransaction()).isNull();
|
||||
}
|
||||
|
||||
@ForPlatform(Platform.H2)
|
||||
@@ -160,15 +151,14 @@ public class TestExecuteComplete extends BaseTestCase {
|
||||
public void no_transaction_expect_threadScopeCleanup() {
|
||||
|
||||
try (Transaction txn = DB.beginTransaction(TxScope.notSupported())) {
|
||||
SpiTransaction txn2 = DefaultTransactionThreadLocal.get("h2");
|
||||
SpiTransaction txn2 = getInScopeTransaction();
|
||||
// The NoTransaction placeholder can normally only occur inside
|
||||
// a scopedTrans. (Class is package private, so check
|
||||
assertThat(txn2.toString()).contains("NoTransaction");
|
||||
assertThat(txn2.toString()).contains("NoTransaction");
|
||||
}
|
||||
|
||||
SpiTransaction txn = DefaultTransactionThreadLocal.get("h2");
|
||||
assertThat(txn).isNull();
|
||||
assertThat(getInScopeTransaction()).isNull();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user