From 7ac583117e66414ed2193002953c07303eede1dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Shengyuan=20Lu=20=E5=8D=A2=E5=A3=B0=E8=BF=9C?= Date: Tue, 30 Jun 2020 10:27:27 +0800 Subject: [PATCH] Add DasTransactional.rollback and DasRunner (#24) * Add DasTransactional.rollback and DasRunner * scope of junit dependency back to test * Add testNestedTransaction and testNestedTransactionException in DasRunnerTest --- das-client/pom.xml | 15 ++- .../main/java/com/ppdai/das/client/Hints.java | 9 ++ .../client/annotation/DasTransactional.java | 6 + .../DasTransactionInterceptor.java | 13 ++- .../java/com/ppdai/das/core/HintEnum.java | 7 +- .../core/client/DalTransactionManager.java | 6 +- .../com/ppdai/das/core/test/DasRunner.java | 32 ++++++ .../ppdai/das/client/AllDasClientTests.java | 106 +++++++++--------- .../java/com/ppdai/das/core/test/DaoBean.java | 31 +++++ .../ppdai/das/core/test/DasRunnerTest.java | 76 +++++++++++++ 10 files changed, 245 insertions(+), 56 deletions(-) create mode 100644 das-client/src/main/java/com/ppdai/das/core/test/DasRunner.java create mode 100644 das-client/src/test/java/com/ppdai/das/core/test/DaoBean.java create mode 100644 das-client/src/test/java/com/ppdai/das/core/test/DasRunnerTest.java diff --git a/das-client/pom.xml b/das-client/pom.xml index 6aa4f10..d597b2e 100644 --- a/das-client/pom.xml +++ b/das-client/pom.xml @@ -23,6 +23,7 @@ 0.12.0 23.0 4.3.8.RELEASE + 1.5.2.RELEASE UTF-8 @@ -40,7 +41,7 @@ junit junit ${junit-version} - test + provided javax.persistence @@ -115,6 +116,18 @@ guava ${guava-version} + + org.springframework + spring-test + ${spring-version} + provided + + + org.springframework.boot + spring-boot-test + ${spring-boot-version} + provided + src/main/java diff --git a/das-client/src/main/java/com/ppdai/das/client/Hints.java b/das-client/src/main/java/com/ppdai/das/client/Hints.java index 0163ec1..e4e5b76 100644 --- a/das-client/src/main/java/com/ppdai/das/client/Hints.java +++ b/das-client/src/main/java/com/ppdai/das/client/Hints.java @@ -64,6 +64,15 @@ public Hints diagnose() { return this; } + public Hints rollbackOnly() { + set(HintEnum.rollbackOnly); + return this; + } + + public boolean isRollbackOnly() { + return is(HintEnum.rollbackOnly); + } + /** * Returns {@code DasDiagnose} instance. * diff --git a/das-client/src/main/java/com/ppdai/das/client/annotation/DasTransactional.java b/das-client/src/main/java/com/ppdai/das/client/annotation/DasTransactional.java index 8225a0c..bd34815 100644 --- a/das-client/src/main/java/com/ppdai/das/client/annotation/DasTransactional.java +++ b/das-client/src/main/java/com/ppdai/das/client/annotation/DasTransactional.java @@ -12,4 +12,10 @@ * @return logic database name defined in dal.config/xml */ String logicDbName(); + + /** + * + * @return rollback transaction or not, default false + */ + boolean rollback() default false; } diff --git a/das-client/src/main/java/com/ppdai/das/client/transaction/DasTransactionInterceptor.java b/das-client/src/main/java/com/ppdai/das/client/transaction/DasTransactionInterceptor.java index a0111b1..2dee96f 100644 --- a/das-client/src/main/java/com/ppdai/das/client/transaction/DasTransactionInterceptor.java +++ b/das-client/src/main/java/com/ppdai/das/client/transaction/DasTransactionInterceptor.java @@ -63,7 +63,9 @@ public Object intercept(final Object obj, final Method method, final Object[] ar } final AtomicReference result = new AtomicReference<>(); - + if(getRollback(method)) { + hints.rollbackOnly(); + } DasClientFactory.getClient(getLogicDbName(method)).execute(() -> { try { result.set(proxy.invokeSuper(obj, args)); @@ -89,4 +91,13 @@ private String getLogicDbName(Method method) { return method.getAnnotation(DasTransactional.class).logicDbName(); } + + private boolean getRollback(Method method) { + DasTransactional tran = method.getAnnotation(DasTransactional.class); + if(tran != null) { + return tran.rollback(); + } + + return method.getAnnotation(DasTransactional.class).rollback(); + } } diff --git a/das-client/src/main/java/com/ppdai/das/core/HintEnum.java b/das-client/src/main/java/com/ppdai/das/core/HintEnum.java index 331960a..77a0b25 100644 --- a/das-client/src/main/java/com/ppdai/das/core/HintEnum.java +++ b/das-client/src/main/java/com/ppdai/das/core/HintEnum.java @@ -270,5 +270,10 @@ public enum HintEnum { /** * Columns to sort in-memory */ - sortColumns + sortColumns, + + /** + * Rollback transaction explicitly + */ + rollbackOnly } diff --git a/das-client/src/main/java/com/ppdai/das/core/client/DalTransactionManager.java b/das-client/src/main/java/com/ppdai/das/core/client/DalTransactionManager.java index 0293aa6..ff857e4 100644 --- a/das-client/src/main/java/com/ppdai/das/core/client/DalTransactionManager.java +++ b/das-client/src/main/java/com/ppdai/das/core/client/DalTransactionManager.java @@ -169,7 +169,11 @@ public T doInTransaction(ConnectionAction action, Hints hints)throws SQLE result = action.execute(); - endTransaction(level); + if(hints.isRollbackOnly()) { + rollbackTransaction(); + } else { + endTransaction(level); + } } catch (Throwable e) { action.error(e); rollbackTransaction(); diff --git a/das-client/src/main/java/com/ppdai/das/core/test/DasRunner.java b/das-client/src/main/java/com/ppdai/das/core/test/DasRunner.java new file mode 100644 index 0000000..594df04 --- /dev/null +++ b/das-client/src/main/java/com/ppdai/das/core/test/DasRunner.java @@ -0,0 +1,32 @@ +package com.ppdai.das.core.test; + +import com.ppdai.das.core.client.DalTransactionManager; +import org.junit.runners.model.InitializationError; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * Use this Runner to support declarative rollback in JUnit. + * The DasRunner is-a SpringJUnit4ClassRunner. + * + * sample: + * @Test + * @DasTransactional(logicDbName="MySqlSimple", rollback = true) + * public void test() throws SQLException { + * dao.insert(list); + * } + * + * @see {@link com.ppdai.das.client.annotation.DasTransactional}. + */ +public class DasRunner extends SpringJUnit4ClassRunner { + public DasRunner(Class clazz) throws InitializationError { + super(clazz); + } + + @Override + protected Object createTest() throws Exception { + Class clz = this.getTestClass().getJavaClass(); + Object testInstance = DalTransactionManager.create(clz); + this.getTestContextManager().prepareTestInstance(testInstance); + return testInstance; + } +} diff --git a/das-client/src/test/java/com/ppdai/das/client/AllDasClientTests.java b/das-client/src/test/java/com/ppdai/das/client/AllDasClientTests.java index f48272a..3910238 100644 --- a/das-client/src/test/java/com/ppdai/das/client/AllDasClientTests.java +++ b/das-client/src/test/java/com/ppdai/das/client/AllDasClientTests.java @@ -1,52 +1,54 @@ -package com.ppdai.das.client; - -import com.ppdai.das.client.transaction.normal.BaseDalTransactionalAnnotationTest; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; -import org.junit.runners.Suite.SuiteClasses; - -import com.ppdai.das.client.delegate.datasync.DataSyncConfigurationTest; -import com.ppdai.das.client.delegate.datasync.SequenceGeneratorTest; -import com.ppdai.das.client.sqlbuilder.AllSqlBuilderTests; -import com.ppdai.das.client.sqlbuilder.SqlBuilderSerializeTest; -import com.ppdai.das.configure.SlaveFreshnessScannerMysqlTest; -import com.ppdai.das.core.datasource.RefreshableDataSourceTest; -import com.ppdai.das.core.helper.ShardingManagerTest; -import com.ppdai.das.strategy.AllStrategyTests; -import com.ppdai.das.util.ConvertUtilsTest; - -@RunWith(Suite.class) -@SuiteClasses({ - AllSqlBuilderTests.class, - AllStrategyTests.class, - AllTableDaoTests.class, - - BatchCallBuilderTest.class, - CallBuilderTest.class, - - DasClientTest.class, - DasClientDBTest.class, - DasClientTableTest.class, - DasClientDbTableTest.class, - DasClientDbTableZeroTest.class, - DasClientDiagnoseTest.class, - - SqlBuilderDBShardTest.class, - SqlBuilderTableShardTest.class, - SqlBuilderDbTableShardTest.class, - - DistributedTransactionDbTest.class, - DistributedTransactionTableTest.class, - NestedTransactionTest.class, - BaseDalTransactionalAnnotationTest.class, - - ConvertUtilsTest.class, - DataSyncConfigurationTest.class, - SequenceGeneratorTest.class, - ShardingManagerTest.class, - RefreshableDataSourceTest.class, - SqlBuilderSerializeTest.class, - SlaveFreshnessScannerMysqlTest.class, -}) -public class AllDasClientTests { -} +package com.ppdai.das.client; + +import com.ppdai.das.client.transaction.normal.BaseDalTransactionalAnnotationTest; +import com.ppdai.das.core.test.DasRunnerTest; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +import com.ppdai.das.client.delegate.datasync.DataSyncConfigurationTest; +import com.ppdai.das.client.delegate.datasync.SequenceGeneratorTest; +import com.ppdai.das.client.sqlbuilder.AllSqlBuilderTests; +import com.ppdai.das.client.sqlbuilder.SqlBuilderSerializeTest; +import com.ppdai.das.configure.SlaveFreshnessScannerMysqlTest; +import com.ppdai.das.core.datasource.RefreshableDataSourceTest; +import com.ppdai.das.core.helper.ShardingManagerTest; +import com.ppdai.das.strategy.AllStrategyTests; +import com.ppdai.das.util.ConvertUtilsTest; + +@RunWith(Suite.class) +@SuiteClasses({ + AllSqlBuilderTests.class, + AllStrategyTests.class, + AllTableDaoTests.class, + + BatchCallBuilderTest.class, + CallBuilderTest.class, + + DasClientTest.class, + DasClientDBTest.class, + DasClientTableTest.class, + DasClientDbTableTest.class, + DasClientDbTableZeroTest.class, + DasClientDiagnoseTest.class, + + SqlBuilderDBShardTest.class, + SqlBuilderTableShardTest.class, + SqlBuilderDbTableShardTest.class, + + DasRunnerTest.class, + DistributedTransactionDbTest.class, + DistributedTransactionTableTest.class, + NestedTransactionTest.class, + BaseDalTransactionalAnnotationTest.class, + + ConvertUtilsTest.class, + DataSyncConfigurationTest.class, + SequenceGeneratorTest.class, + ShardingManagerTest.class, + RefreshableDataSourceTest.class, + SqlBuilderSerializeTest.class, + SlaveFreshnessScannerMysqlTest.class, +}) +public class AllDasClientTests { +} diff --git a/das-client/src/test/java/com/ppdai/das/core/test/DaoBean.java b/das-client/src/test/java/com/ppdai/das/core/test/DaoBean.java new file mode 100644 index 0000000..ef8a43f --- /dev/null +++ b/das-client/src/test/java/com/ppdai/das/core/test/DaoBean.java @@ -0,0 +1,31 @@ +package com.ppdai.das.core.test; + +import com.ppdai.das.client.DasClient; +import com.ppdai.das.client.DasClientFactory; +import com.ppdai.das.client.Person; +import com.ppdai.das.client.annotation.DasTransactional; +import org.springframework.stereotype.Component; + +import java.sql.SQLException; + +@Component +public class DaoBean { + private static final String DB_NAME = "MySqlSimple"; + + @DasTransactional(logicDbName = DB_NAME) + public void commitMethod() throws SQLException { + insert(); + } + + @DasTransactional(logicDbName = DB_NAME, rollback = true) + public void rollbackMethod() throws SQLException { + insert(); + } + + private void insert() throws SQLException { + DasClient dasClient = DasClientFactory.getClient(DB_NAME); + Person p = new Person(); + p.setName("name"); + dasClient.insert(p); + } +} diff --git a/das-client/src/test/java/com/ppdai/das/core/test/DasRunnerTest.java b/das-client/src/test/java/com/ppdai/das/core/test/DasRunnerTest.java new file mode 100644 index 0000000..a29958b --- /dev/null +++ b/das-client/src/test/java/com/ppdai/das/core/test/DasRunnerTest.java @@ -0,0 +1,76 @@ +package com.ppdai.das.core.test; + +import com.ppdai.das.client.DasClient; +import com.ppdai.das.client.DasClientFactory; +import com.ppdai.das.client.Person; +import com.ppdai.das.client.SqlBuilder; +import com.ppdai.das.client.annotation.DasTransactional; +import com.ppdai.das.client.transaction.DasTransactionalEnabler; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; + +import java.sql.SQLException; + +@RunWith(DasRunner.class) +@ContextConfiguration(classes = {DasTransactionalEnabler.class, DasRunnerTest.class, DaoBean.class}) +@SpringBootTest +public class DasRunnerTest { + + private static final String DB_NAME = "MySqlSimple"; + private DasClient dasClient; + private boolean isRollback = false; + private long count = 0; + + @Autowired + DaoBean daoBean; + + @Before + public void before() throws SQLException { + dasClient = DasClientFactory.getClient(DB_NAME); + count = dasClient.queryObject(SqlBuilder.selectCount().from(Person.PERSON).intoObject()); + } + + @After + public void after() throws SQLException { + long now = dasClient.queryObject(SqlBuilder.selectCount().from(Person.PERSON).intoObject()); + Assert.assertEquals(now, isRollback ? count : count + 1); + } + + @Test + @DasTransactional(logicDbName = DB_NAME, rollback = true) + public void testRollback() throws SQLException { + isRollback = true; + Person p = new Person(); + p.setName("name"); + dasClient.insert(p); + } + + @Test + @DasTransactional(logicDbName = DB_NAME) + public void testCommit() throws SQLException { + isRollback = false; + Person p = new Person(); + p.setName("name"); + dasClient.insert(p); + } + + @Test + @DasTransactional(logicDbName = DB_NAME, rollback = true) + public void testNestedTransaction() throws SQLException { + isRollback = true; + daoBean.commitMethod(); + } + + @Test(expected = SQLException.class) + @DasTransactional(logicDbName = DB_NAME, rollback = false) + public void testNestedTransactionException() throws SQLException { + isRollback = true; + daoBean.rollbackMethod(); + } +}