This is an automated email from the ASF dual-hosted git repository. zhangliang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push: new 0c36db69526 Add DialectDatabaseMetaData.isSupportAutoCommitInNestedTransaction (#35170) 0c36db69526 is described below commit 0c36db69526b8174cf526c0bc6ae3b2c29201837 Author: Liang Zhang <zhangli...@apache.org> AuthorDate: Sat Apr 12 21:11:08 2025 +0800 Add DialectDatabaseMetaData.isSupportAutoCommitInNestedTransaction (#35170) * Add DialectDatabaseMetaData.isSupportAutoCommitInNestedTransaction * Add DialectDatabaseMetaData.isSupportAutoCommitInNestedTransaction * Add DialectDatabaseMetaData.isSupportAutoCommitInNestedTransaction * Add DialectDatabaseMetaData.isSupportAutoCommitInNestedTransaction --- .../metadata/database/DialectDatabaseMetaData.java | 9 ++++++++ .../metadata/database/MySQLDatabaseMetaData.java | 5 +++++ .../transaction/TransactionBackendHandler.java | 25 +++++++++++----------- .../handler/ProxyBackendHandlerFactoryTest.java | 1 + .../TransactionBackendHandlerFactoryTest.java | 6 ++++++ .../transaction/TransactionBackendHandlerTest.java | 5 +++++ 6 files changed, 38 insertions(+), 13 deletions(-) diff --git a/infra/database/core/src/main/java/org/apache/shardingsphere/infra/database/core/metadata/database/DialectDatabaseMetaData.java b/infra/database/core/src/main/java/org/apache/shardingsphere/infra/database/core/metadata/database/DialectDatabaseMetaData.java index 00a2f9fa792..4157a607c00 100644 --- a/infra/database/core/src/main/java/org/apache/shardingsphere/infra/database/core/metadata/database/DialectDatabaseMetaData.java +++ b/infra/database/core/src/main/java/org/apache/shardingsphere/infra/database/core/metadata/database/DialectDatabaseMetaData.java @@ -148,6 +148,15 @@ public interface DialectDatabaseMetaData extends DatabaseTypedSPI { return false; } + /** + * Whether support auto commit when nested transaction. + * + * @return support or not + */ + default boolean isSupportAutoCommitInNestedTransaction() { + return false; + } + /** * Whether support DDL in XA transaction. * diff --git a/infra/database/type/mysql/src/main/java/org/apache/shardingsphere/infra/database/mysql/metadata/database/MySQLDatabaseMetaData.java b/infra/database/type/mysql/src/main/java/org/apache/shardingsphere/infra/database/mysql/metadata/database/MySQLDatabaseMetaData.java index 973dad7d180..b0eb71727d8 100644 --- a/infra/database/type/mysql/src/main/java/org/apache/shardingsphere/infra/database/mysql/metadata/database/MySQLDatabaseMetaData.java +++ b/infra/database/type/mysql/src/main/java/org/apache/shardingsphere/infra/database/mysql/metadata/database/MySQLDatabaseMetaData.java @@ -93,6 +93,11 @@ public final class MySQLDatabaseMetaData implements DialectDatabaseMetaData { return true; } + @Override + public boolean isSupportAutoCommitInNestedTransaction() { + return true; + } + @Override public String getDatabaseType() { return "MySQL"; diff --git a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/transaction/TransactionBackendHandler.java b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/transaction/TransactionBackendHandler.java index 13fdcacb897..d7e521e0552 100644 --- a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/transaction/TransactionBackendHandler.java +++ b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/transaction/TransactionBackendHandler.java @@ -17,8 +17,8 @@ package org.apache.shardingsphere.proxy.backend.handler.transaction; +import org.apache.shardingsphere.infra.database.core.metadata.database.DialectDatabaseMetaData; import org.apache.shardingsphere.infra.database.core.type.DatabaseTypeRegistry; -import org.apache.shardingsphere.infra.database.mysql.type.MySQLDatabaseType; import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions; import org.apache.shardingsphere.infra.exception.dialect.exception.transaction.InTransactionException; import org.apache.shardingsphere.proxy.backend.connector.TransactionManager; @@ -44,7 +44,7 @@ import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; /** - * Do transaction operation. + * Transaction backend handler. */ public final class TransactionBackendHandler implements ProxyBackendHandler { @@ -52,14 +52,17 @@ public final class TransactionBackendHandler implements ProxyBackendHandler { private final TransactionOperationType operationType; - private final TransactionManager backendTransactionManager; - private final ConnectionSession connectionSession; + private final DialectDatabaseMetaData dialectDatabaseMetaData; + + private final TransactionManager backendTransactionManager; + public TransactionBackendHandler(final TCLStatement tclStatement, final TransactionOperationType operationType, final ConnectionSession connectionSession) { this.tclStatement = tclStatement; this.operationType = operationType; this.connectionSession = connectionSession; + dialectDatabaseMetaData = new DatabaseTypeRegistry(connectionSession.getProtocolType()).getDialectDatabaseMetaData(); backendTransactionManager = new BackendTransactionManager(connectionSession.getDatabaseConnectionManager()); } @@ -96,9 +99,9 @@ public final class TransactionBackendHandler implements ProxyBackendHandler { private void handleBegin() throws SQLException { if (connectionSession.getTransactionStatus().isInTransaction()) { - if (connectionSession.getProtocolType() instanceof MySQLDatabaseType) { + if (dialectDatabaseMetaData.isSupportAutoCommitInNestedTransaction()) { backendTransactionManager.commit(); - } else if (isSchemaSupportedDatabaseType()) { + } else if (dialectDatabaseMetaData.getDefaultSchema().isPresent()) { throw new InTransactionException(); } } @@ -106,27 +109,23 @@ public final class TransactionBackendHandler implements ProxyBackendHandler { } private void handleSavepoint() throws SQLException { - ShardingSpherePreconditions.checkState(connectionSession.getTransactionStatus().isInTransaction() || !isSchemaSupportedDatabaseType(), + ShardingSpherePreconditions.checkState(connectionSession.getTransactionStatus().isInTransaction() || !dialectDatabaseMetaData.getDefaultSchema().isPresent(), () -> new SQLFeatureNotSupportedException("SAVEPOINT can only be used in transaction blocks")); backendTransactionManager.setSavepoint(((SavepointStatement) tclStatement).getSavepointName()); } private void handleRollbackToSavepoint() throws SQLException { - ShardingSpherePreconditions.checkState(connectionSession.getTransactionStatus().isInTransaction() || !isSchemaSupportedDatabaseType(), + ShardingSpherePreconditions.checkState(connectionSession.getTransactionStatus().isInTransaction() || !dialectDatabaseMetaData.getDefaultSchema().isPresent(), () -> new SQLFeatureNotSupportedException("ROLLBACK TO SAVEPOINT can only be used in transaction blocks")); backendTransactionManager.rollbackTo(((RollbackStatement) tclStatement).getSavepointName().get()); } private void handleReleaseSavepoint() throws SQLException { - ShardingSpherePreconditions.checkState(connectionSession.getTransactionStatus().isInTransaction() || !isSchemaSupportedDatabaseType(), + ShardingSpherePreconditions.checkState(connectionSession.getTransactionStatus().isInTransaction() || !dialectDatabaseMetaData.getDefaultSchema().isPresent(), () -> new SQLFeatureNotSupportedException("RELEASE SAVEPOINT can only be used in transaction blocks")); backendTransactionManager.releaseSavepoint(((ReleaseSavepointStatement) tclStatement).getSavepointName()); } - private boolean isSchemaSupportedDatabaseType() { - return new DatabaseTypeRegistry(connectionSession.getProtocolType()).getDialectDatabaseMetaData().getDefaultSchema().isPresent(); - } - private SQLStatement getSQLStatementByCommit() { SQLStatement result = tclStatement; if (connectionSession.getConnectionContext().getTransactionContext().isExceptionOccur()) { diff --git a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/ProxyBackendHandlerFactoryTest.java b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/ProxyBackendHandlerFactoryTest.java index 4a8a642adbe..79326507500 100644 --- a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/ProxyBackendHandlerFactoryTest.java +++ b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/ProxyBackendHandlerFactoryTest.java @@ -99,6 +99,7 @@ class ProxyBackendHandlerFactoryTest { ProxyDatabaseConnectionManager databaseConnectionManager = mock(ProxyDatabaseConnectionManager.class); when(databaseConnectionManager.getConnectionSession()).thenReturn(connectionSession); when(connectionSession.getDatabaseConnectionManager()).thenReturn(databaseConnectionManager); + when(connectionSession.getProtocolType()).thenReturn(databaseType); ContextManager contextManager = mockContextManager(); when(contextManager.getStateContext().getState()).thenReturn(ShardingSphereState.OK); when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager); diff --git a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/transaction/TransactionBackendHandlerFactoryTest.java b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/transaction/TransactionBackendHandlerFactoryTest.java index b325704dab8..212e3ee40de 100644 --- a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/transaction/TransactionBackendHandlerFactoryTest.java +++ b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/transaction/TransactionBackendHandlerFactoryTest.java @@ -19,11 +19,13 @@ package org.apache.shardingsphere.proxy.backend.handler.transaction; import lombok.SneakyThrows; import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext; +import org.apache.shardingsphere.infra.database.core.type.DatabaseType; import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData; import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData; import org.apache.shardingsphere.infra.session.connection.ConnectionContext; import org.apache.shardingsphere.infra.session.connection.transaction.TransactionConnectionContext; import org.apache.shardingsphere.infra.session.query.QueryContext; +import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader; import org.apache.shardingsphere.mode.manager.ContextManager; import org.apache.shardingsphere.proxy.backend.connector.DatabaseConnector; import org.apache.shardingsphere.proxy.backend.connector.DatabaseConnectorFactory; @@ -62,11 +64,14 @@ import static org.mockito.Mockito.when; @StaticMockSettings({ProxyContext.class, DatabaseConnectorFactory.class}) class TransactionBackendHandlerFactoryTest { + private final DatabaseType databaseType = TypedSPILoader.getService(DatabaseType.class, "FIXTURE"); + @Test void assertTransactionBackendHandlerReturnedWhenTCLStatementInstanceOfCommitStatement() { ConnectionSession connectionSession = mock(ConnectionSession.class, Answers.RETURNS_DEEP_STUBS); ProxyDatabaseConnectionManager databaseConnectionManager = mock(ProxyDatabaseConnectionManager.class); when(connectionSession.getDatabaseConnectionManager()).thenReturn(databaseConnectionManager); + when(connectionSession.getProtocolType()).thenReturn(databaseType); when(databaseConnectionManager.getConnectionSession()).thenReturn(connectionSession); when(databaseConnectionManager.getConnectionSession().getConnectionContext().getTransactionContext()).thenReturn(new TransactionConnectionContext()); SQLStatementContext context = mock(SQLStatementContext.class); @@ -85,6 +90,7 @@ class TransactionBackendHandlerFactoryTest { ConnectionSession connectionSession = mock(ConnectionSession.class, Answers.RETURNS_DEEP_STUBS); ProxyDatabaseConnectionManager databaseConnectionManager = mock(ProxyDatabaseConnectionManager.class); when(connectionSession.getDatabaseConnectionManager()).thenReturn(databaseConnectionManager); + when(connectionSession.getProtocolType()).thenReturn(databaseType); when(databaseConnectionManager.getConnectionSession()).thenReturn(connectionSession); when(databaseConnectionManager.getConnectionSession().getConnectionContext().getTransactionContext()).thenReturn(new TransactionConnectionContext()); when(connectionSession.getDatabaseConnectionManager().getConnectionSession().getConnectionContext().getTransactionContext()).thenReturn(new TransactionConnectionContext()); diff --git a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/transaction/TransactionBackendHandlerTest.java b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/transaction/TransactionBackendHandlerTest.java index 4ab0b3005b6..182b9a5b9f7 100644 --- a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/transaction/TransactionBackendHandlerTest.java +++ b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/transaction/TransactionBackendHandlerTest.java @@ -17,7 +17,9 @@ package org.apache.shardingsphere.proxy.backend.handler.transaction; +import org.apache.shardingsphere.infra.database.core.type.DatabaseType; import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData; +import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader; import org.apache.shardingsphere.mode.manager.ContextManager; import org.apache.shardingsphere.proxy.backend.connector.ProxyDatabaseConnectionManager; import org.apache.shardingsphere.proxy.backend.context.ProxyContext; @@ -45,12 +47,15 @@ import static org.mockito.Mockito.when; @StaticMockSettings(ProxyContext.class) class TransactionBackendHandlerTest { + private final DatabaseType databaseType = TypedSPILoader.getService(DatabaseType.class, "FIXTURE"); + private final ConnectionSession connectionSession = mock(ConnectionSession.class, RETURNS_DEEP_STUBS); @Test void assertExecute() throws SQLException { ProxyDatabaseConnectionManager databaseConnectionManager = mock(ProxyDatabaseConnectionManager.class); when(connectionSession.getDatabaseConnectionManager()).thenReturn(databaseConnectionManager); + when(connectionSession.getProtocolType()).thenReturn(databaseType); when(databaseConnectionManager.getConnectionSession()).thenReturn(connectionSession); ContextManager contextManager = mockContextManager(); when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);