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 4123d57278a Add test cases for state, TCL, RAL, label and variable 
handlers (#37486)
4123d57278a is described below

commit 4123d57278a0ec204ea7d123e2cbb0e268b7e0f4
Author: Liang Zhang <[email protected]>
AuthorDate: Wed Dec 24 10:47:56 2025 +0800

    Add test cases for state, TCL, RAL, label and variable handlers (#37486)
    
    * Add test cases for state, TCL, RAL, label and variable handlers
    
    * Add test cases for state, TCL, RAL, label and variable handlers
    
    * Add test cases for state, TCL, RAL, label and variable handlers
---
 .../variable/charset/CharsetSetExecutorTest.java   |  75 +++++++++
 .../session/SessionVariableRecordExecutorTest.java |  89 +++++++++++
 .../label/LabelComputeNodeExecutorTest.java        |  92 +++++++++++
 .../label/UnlabelComputeNodeExecutorTest.java      |  95 +++++++++++
 .../RefreshDatabaseMetaDataExecutorTest.java       |  67 ++++++++
 .../refresh/RefreshTableMetaDataExecutorTest.java  | 173 +++++++++++++++++++++
 .../BeginTransactionProxyBackendHandlerTest.java   | 137 ++++++++++++++++
 .../local/type/CommitProxyBackendHandlerTest.java  | 100 ++++++++++++
 .../ReleaseSavepointProxyBackendHandlerTest.java   | 114 ++++++++++++++
 .../RollbackSavepointProxyBackendHandlerTest.java  | 111 +++++++++++++
 .../type/SetAutoCommitProxyBackendHandlerTest.java | 149 ++++++++++++++++++
 .../type/SetSavepointProxyBackendHandlerTest.java  | 111 +++++++++++++
 .../SetTransactionProxyBackendHandlerTest.java     | 129 +++++++++++++++
 .../ReadOnlyProxyStateCheckerTest.java}            |  24 ++-
 .../UnavailableProxyStateCheckerTest.java}         |  15 +-
 .../sysvar/provider/VersionValueProviderTest.java  |   4 +-
 16 files changed, 1469 insertions(+), 16 deletions(-)

diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/variable/charset/CharsetSetExecutorTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/variable/charset/CharsetSetExecutorTest.java
new file mode 100644
index 00000000000..e7fdce73818
--- /dev/null
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/variable/charset/CharsetSetExecutorTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package 
org.apache.shardingsphere.proxy.backend.handler.admin.executor.variable.charset;
+
+import io.netty.util.Attribute;
+import io.netty.util.AttributeMap;
+import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import org.apache.shardingsphere.database.protocol.constant.CommonConstants;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import 
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
+import 
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings(DatabaseTypedSPILoader.class)
+class CharsetSetExecutorTest {
+    
+    private final DatabaseType databaseType = mock(DatabaseType.class);
+    
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    @Test
+    void assertSetWhenProviderPresentAndVariableMatched() {
+        CharsetVariableProvider provider = mock(CharsetVariableProvider.class);
+        
when(provider.getCharsetVariables()).thenReturn(Collections.singletonList("character_set_client"));
+        when(provider.parseCharset("utf8")).thenReturn(StandardCharsets.UTF_8);
+        when(DatabaseTypedSPILoader.findService(CharsetVariableProvider.class, 
databaseType)).thenReturn(Optional.of(provider));
+        AttributeMap attributeMap = mock(AttributeMap.class);
+        Attribute attribute = mock(Attribute.class);
+        
when(attributeMap.attr(CommonConstants.CHARSET_ATTRIBUTE_KEY)).thenReturn(attribute);
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        when(connectionSession.getAttributeMap()).thenReturn(attributeMap);
+        new CharsetSetExecutor(databaseType, 
connectionSession).set("CHARACTER_SET_CLIENT", "utf8");
+        verify(attribute).set(StandardCharsets.UTF_8);
+    }
+    
+    @Test
+    void assertSetWhenProviderAbsentOrVariableMismatch() {
+        when(DatabaseTypedSPILoader.findService(CharsetVariableProvider.class, 
databaseType)).thenReturn(Optional.empty());
+        assertDoesNotThrow(() -> new CharsetSetExecutor(databaseType, 
mock()).set("other_variable", "utf8"));
+    }
+    
+    @Test
+    void assertSetWhenVariableNotMatched() {
+        CharsetVariableProvider provider = mock(CharsetVariableProvider.class);
+        
when(provider.getCharsetVariables()).thenReturn(Collections.singletonList("character_set_server"));
+        when(DatabaseTypedSPILoader.findService(CharsetVariableProvider.class, 
databaseType)).thenReturn(Optional.of(provider));
+        assertDoesNotThrow(() -> new CharsetSetExecutor(databaseType, 
mock()).set("character_set_client", "utf8"));
+    }
+}
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/variable/session/SessionVariableRecordExecutorTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/variable/session/SessionVariableRecordExecutorTest.java
new file mode 100644
index 00000000000..e43dd809f55
--- /dev/null
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/variable/session/SessionVariableRecordExecutorTest.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package 
org.apache.shardingsphere.proxy.backend.handler.admin.executor.variable.session;
+
+import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import 
org.apache.shardingsphere.proxy.backend.session.RequiredSessionVariableRecorder;
+import 
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
+import 
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings(DatabaseTypedSPILoader.class)
+class SessionVariableRecordExecutorTest {
+    
+    private final DatabaseType databaseType = mock(DatabaseType.class);
+    
+    @Test
+    void assertRecordSingleVariableWhenNeedReplay() {
+        ReplayedSessionVariableProvider provider = 
mock(ReplayedSessionVariableProvider.class);
+        when(provider.isNeedToReplay("autocommit")).thenReturn(true);
+        
when(DatabaseTypedSPILoader.findService(ReplayedSessionVariableProvider.class, 
databaseType)).thenReturn(Optional.of(provider));
+        RequiredSessionVariableRecorder recorder = 
mock(RequiredSessionVariableRecorder.class);
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        
when(connectionSession.getRequiredSessionVariableRecorder()).thenReturn(recorder);
+        new SessionVariableRecordExecutor(databaseType, 
connectionSession).recordVariable("autocommit", "1");
+        verify(recorder).setVariable("autocommit", "1");
+    }
+    
+    @Test
+    void assertSkipSingleVariableWhenNotNeedReplay() {
+        ReplayedSessionVariableProvider provider = 
mock(ReplayedSessionVariableProvider.class);
+        
when(DatabaseTypedSPILoader.findService(ReplayedSessionVariableProvider.class, 
databaseType)).thenReturn(Optional.of(provider));
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        assertDoesNotThrow(() -> new 
SessionVariableRecordExecutor(databaseType, 
connectionSession).recordVariable("sql_mode", "STRICT_ALL_TABLES"));
+    }
+    
+    @Test
+    void assertRecordVariableWithAllWhenProviderAbsent() {
+        
when(DatabaseTypedSPILoader.findService(ReplayedSessionVariableProvider.class, 
databaseType)).thenReturn(Optional.empty());
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        assertDoesNotThrow(() -> new 
SessionVariableRecordExecutor(databaseType, 
connectionSession).recordVariable(Collections.singletonMap("var_a", "1")));
+    }
+    
+    @Test
+    void assertRecordOnlyNeededVariables() {
+        ReplayedSessionVariableProvider provider = 
mock(ReplayedSessionVariableProvider.class);
+        when(provider.isNeedToReplay("var_a")).thenReturn(true);
+        when(provider.isNeedToReplay("var_b")).thenReturn(false);
+        
when(DatabaseTypedSPILoader.findService(ReplayedSessionVariableProvider.class, 
databaseType)).thenReturn(Optional.of(provider));
+        RequiredSessionVariableRecorder recorder = 
mock(RequiredSessionVariableRecorder.class);
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        
when(connectionSession.getRequiredSessionVariableRecorder()).thenReturn(recorder);
+        Map<String, String> variables = new HashMap<>(2, 1F);
+        variables.put("var_a", "1");
+        variables.put("var_b", "2");
+        new SessionVariableRecordExecutor(databaseType, 
connectionSession).recordVariable(variables);
+        verify(recorder).setVariable("var_a", "1");
+        verify(recorder, never()).setVariable("var_b", "2");
+    }
+}
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/label/LabelComputeNodeExecutorTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/label/LabelComputeNodeExecutorTest.java
new file mode 100644
index 00000000000..0822cb1dcc4
--- /dev/null
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/label/LabelComputeNodeExecutorTest.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package 
org.apache.shardingsphere.proxy.backend.handler.distsql.ral.updatable.label;
+
+import 
org.apache.shardingsphere.distsql.handler.engine.update.DistSQLUpdateExecutor;
+import 
org.apache.shardingsphere.distsql.statement.type.ral.updatable.LabelComputeNodeStatement;
+import org.apache.shardingsphere.infra.instance.ClusterInstanceRegistry;
+import org.apache.shardingsphere.infra.instance.ComputeNodeInstance;
+import org.apache.shardingsphere.infra.instance.ComputeNodeInstanceContext;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.mode.manager.ContextManager;
+import 
org.apache.shardingsphere.mode.manager.cluster.persist.facade.ClusterPersistServiceFacade;
+import 
org.apache.shardingsphere.mode.manager.cluster.persist.service.ClusterComputeNodePersistService;
+import org.apache.shardingsphere.mode.persist.PersistServiceFacade;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class LabelComputeNodeExecutorTest {
+    
+    private final LabelComputeNodeExecutor executor = 
(LabelComputeNodeExecutor) 
TypedSPILoader.getService(DistSQLUpdateExecutor.class, 
LabelComputeNodeStatement.class);
+    
+    @Test
+    void assertExecuteUpdateWhenInstanceAbsent() {
+        ContextManager contextManager = mock(ContextManager.class);
+        ComputeNodeInstanceContext instanceContext = 
mock(ComputeNodeInstanceContext.class);
+        ClusterInstanceRegistry clusterInstanceRegistry = 
mock(ClusterInstanceRegistry.class);
+        
when(contextManager.getComputeNodeInstanceContext()).thenReturn(instanceContext);
+        
when(instanceContext.getClusterInstanceRegistry()).thenReturn(clusterInstanceRegistry);
+        
when(clusterInstanceRegistry.find("instance-id")).thenReturn(Optional.empty());
+        assertDoesNotThrow(() -> executor.executeUpdate(new 
LabelComputeNodeStatement(true, "instance-id", 
Collections.singletonList("label_a")), contextManager));
+    }
+    
+    @Test
+    void assertExecuteUpdateWhenOverwriteLabels() {
+        ContextManager contextManager = mock(ContextManager.class);
+        ComputeNodeInstance computeNodeInstance = 
mock(ComputeNodeInstance.class);
+        ClusterComputeNodePersistService computeNodeService = 
mockContextManager(contextManager, computeNodeInstance);
+        ComputeNodeInstanceContext instanceContext = 
contextManager.getComputeNodeInstanceContext();
+        
when(instanceContext.getClusterInstanceRegistry().find("instance-id")).thenReturn(Optional.of(computeNodeInstance));
+        executor.executeUpdate(new LabelComputeNodeStatement(true, 
"instance-id", Arrays.asList("label_a", "label_b")), contextManager);
+        verify(computeNodeService).persistLabels("instance-id", 
Arrays.asList("label_a", "label_b"));
+    }
+    
+    @Test
+    void assertExecuteUpdateWhenNotOverwriteLabels() {
+        ContextManager contextManager = mock(ContextManager.class);
+        ComputeNodeInstance computeNodeInstance = 
mock(ComputeNodeInstance.class);
+        
when(computeNodeInstance.getLabels()).thenReturn(Collections.singletonList("origin_label"));
+        ClusterComputeNodePersistService computeNodeService = 
mockContextManager(contextManager, computeNodeInstance);
+        ComputeNodeInstanceContext instanceContext = 
contextManager.getComputeNodeInstanceContext();
+        
when(instanceContext.getClusterInstanceRegistry().find("instance-id")).thenReturn(Optional.of(computeNodeInstance));
+        executor.executeUpdate(new LabelComputeNodeStatement(false, 
"instance-id", Collections.singletonList("new_label")), contextManager);
+        verify(computeNodeService).persistLabels("instance-id", 
Arrays.asList("new_label", "origin_label"));
+    }
+    
+    private ClusterComputeNodePersistService mockContextManager(final 
ContextManager contextManager, final ComputeNodeInstance computeNodeInstance) {
+        ComputeNodeInstanceContext instanceContext = 
mock(ComputeNodeInstanceContext.class, RETURNS_DEEP_STUBS);
+        
when(instanceContext.getClusterInstanceRegistry().find("instance-id")).thenReturn(Optional.of(computeNodeInstance));
+        
when(contextManager.getComputeNodeInstanceContext()).thenReturn(instanceContext);
+        PersistServiceFacade persistServiceFacade = 
mock(PersistServiceFacade.class);
+        ClusterPersistServiceFacade clusterPersistServiceFacade = 
mock(ClusterPersistServiceFacade.class);
+        ClusterComputeNodePersistService result = 
mock(ClusterComputeNodePersistService.class);
+        
when(clusterPersistServiceFacade.getComputeNodeService()).thenReturn(result);
+        
when(persistServiceFacade.getModeFacade()).thenReturn(clusterPersistServiceFacade);
+        
when(contextManager.getPersistServiceFacade()).thenReturn(persistServiceFacade);
+        return result;
+    }
+}
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/label/UnlabelComputeNodeExecutorTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/label/UnlabelComputeNodeExecutorTest.java
new file mode 100644
index 00000000000..120f37f2816
--- /dev/null
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/label/UnlabelComputeNodeExecutorTest.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package 
org.apache.shardingsphere.proxy.backend.handler.distsql.ral.updatable.label;
+
+import 
org.apache.shardingsphere.distsql.handler.engine.update.DistSQLUpdateExecutor;
+import 
org.apache.shardingsphere.distsql.statement.type.ral.updatable.UnlabelComputeNodeStatement;
+import org.apache.shardingsphere.infra.instance.ClusterInstanceRegistry;
+import org.apache.shardingsphere.infra.instance.ComputeNodeInstance;
+import org.apache.shardingsphere.infra.instance.ComputeNodeInstanceContext;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.mode.manager.ContextManager;
+import 
org.apache.shardingsphere.mode.manager.cluster.persist.facade.ClusterPersistServiceFacade;
+import 
org.apache.shardingsphere.mode.manager.cluster.persist.service.ClusterComputeNodePersistService;
+import org.apache.shardingsphere.mode.persist.PersistServiceFacade;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
+
+class UnlabelComputeNodeExecutorTest {
+    
+    private final UnlabelComputeNodeExecutor executor = 
(UnlabelComputeNodeExecutor) 
TypedSPILoader.getService(DistSQLUpdateExecutor.class, 
UnlabelComputeNodeStatement.class);
+    
+    @Test
+    void assertDoNothingWhenInstanceAbsent() {
+        ContextManager contextManager = mock(ContextManager.class);
+        ComputeNodeInstanceContext instanceContext = 
mock(ComputeNodeInstanceContext.class);
+        ClusterInstanceRegistry clusterInstanceRegistry = 
mock(ClusterInstanceRegistry.class);
+        
when(contextManager.getComputeNodeInstanceContext()).thenReturn(instanceContext);
+        
when(instanceContext.getClusterInstanceRegistry()).thenReturn(clusterInstanceRegistry);
+        
when(clusterInstanceRegistry.find("instance-id")).thenReturn(Optional.empty());
+        PersistServiceFacade persistServiceFacade = 
mock(PersistServiceFacade.class);
+        
when(contextManager.getPersistServiceFacade()).thenReturn(persistServiceFacade);
+        executor.executeUpdate(new UnlabelComputeNodeStatement("instance-id", 
Collections.singletonList("label_a")), contextManager);
+        verifyNoInteractions(persistServiceFacade);
+    }
+    
+    @Test
+    void assertClearLabelsWhenStatementLabelsEmpty() {
+        ContextManager contextManager = mock(ContextManager.class);
+        ComputeNodeInstance computeNodeInstance = 
mock(ComputeNodeInstance.class);
+        ClusterComputeNodePersistService computeNodeService = 
mockContextManager(contextManager, computeNodeInstance);
+        ComputeNodeInstanceContext instanceContext = 
contextManager.getComputeNodeInstanceContext();
+        
when(instanceContext.getClusterInstanceRegistry().find("instance-id")).thenReturn(Optional.of(computeNodeInstance));
+        executor.executeUpdate(new UnlabelComputeNodeStatement("instance-id", 
Collections.emptyList()), contextManager);
+        verify(computeNodeService).persistLabels("instance-id", 
Collections.emptyList());
+    }
+    
+    @Test
+    void assertRemoveSpecifiedLabels() {
+        ContextManager contextManager = mock(ContextManager.class);
+        ComputeNodeInstance computeNodeInstance = 
mock(ComputeNodeInstance.class);
+        
when(computeNodeInstance.getLabels()).thenReturn(Arrays.asList("label_a", 
"label_b"));
+        ClusterComputeNodePersistService computeNodeService = 
mockContextManager(contextManager, computeNodeInstance);
+        ComputeNodeInstanceContext instanceContext = 
contextManager.getComputeNodeInstanceContext();
+        
when(instanceContext.getClusterInstanceRegistry().find("instance-id")).thenReturn(Optional.of(computeNodeInstance));
+        executor.executeUpdate(new UnlabelComputeNodeStatement("instance-id", 
Collections.singletonList("label_b")), contextManager);
+        verify(computeNodeService).persistLabels("instance-id", 
Collections.singletonList("label_a"));
+    }
+    
+    private ClusterComputeNodePersistService mockContextManager(final 
ContextManager contextManager, final ComputeNodeInstance computeNodeInstance) {
+        ComputeNodeInstanceContext instanceContext = 
mock(ComputeNodeInstanceContext.class, RETURNS_DEEP_STUBS);
+        
when(instanceContext.getClusterInstanceRegistry().find("instance-id")).thenReturn(Optional.of(computeNodeInstance));
+        
when(contextManager.getComputeNodeInstanceContext()).thenReturn(instanceContext);
+        PersistServiceFacade persistServiceFacade = 
mock(PersistServiceFacade.class);
+        ClusterPersistServiceFacade clusterPersistServiceFacade = 
mock(ClusterPersistServiceFacade.class);
+        
when(persistServiceFacade.getModeFacade()).thenReturn(clusterPersistServiceFacade);
+        
when(contextManager.getPersistServiceFacade()).thenReturn(persistServiceFacade);
+        ClusterComputeNodePersistService result = 
mock(ClusterComputeNodePersistService.class);
+        
when(clusterPersistServiceFacade.getComputeNodeService()).thenReturn(result);
+        return result;
+    }
+}
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/refresh/RefreshDatabaseMetaDataExecutorTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/refresh/RefreshDatabaseMetaDataExecutorTest.java
new file mode 100644
index 00000000000..3d49c29c4d1
--- /dev/null
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/refresh/RefreshDatabaseMetaDataExecutorTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package 
org.apache.shardingsphere.proxy.backend.handler.distsql.ral.updatable.refresh;
+
+import 
org.apache.shardingsphere.distsql.handler.engine.update.DistSQLUpdateExecutor;
+import 
org.apache.shardingsphere.distsql.statement.type.ral.updatable.RefreshDatabaseMetaDataStatement;
+import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
+import 
org.apache.shardingsphere.infra.metadata.database.schema.util.SystemSchemaUtils;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.mode.manager.ContextManager;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class RefreshDatabaseMetaDataExecutorTest {
+    
+    private final RefreshDatabaseMetaDataExecutor executor = 
(RefreshDatabaseMetaDataExecutor) 
TypedSPILoader.getService(DistSQLUpdateExecutor.class, 
RefreshDatabaseMetaDataStatement.class);
+    
+    @Test
+    void assertRefreshSpecifiedDatabase() {
+        ContextManager contextManager = mock(ContextManager.class);
+        ShardingSphereDatabase database = mock(ShardingSphereDatabase.class);
+        when(contextManager.getDatabase("db0")).thenReturn(database);
+        try (MockedStatic<SystemSchemaUtils> mockedStatic = 
mockStatic(SystemSchemaUtils.class)) {
+            mockedStatic.when(() -> 
SystemSchemaUtils.isSystemSchema(database)).thenReturn(false);
+            executor.executeUpdate(new RefreshDatabaseMetaDataStatement("db0", 
false), contextManager);
+            verify(contextManager).reloadDatabase(database);
+        }
+    }
+    
+    @Test
+    void assertRefreshAllDatabasesExceptSystem() {
+        ContextManager contextManager = mock(ContextManager.class, 
RETURNS_DEEP_STUBS);
+        ShardingSphereDatabase systemDatabase = 
mock(ShardingSphereDatabase.class);
+        ShardingSphereDatabase normalDatabase = 
mock(ShardingSphereDatabase.class);
+        Collection<ShardingSphereDatabase> databases = 
Arrays.asList(systemDatabase, normalDatabase);
+        
when(contextManager.getMetaDataContexts().getMetaData().getAllDatabases()).thenReturn(databases);
+        try (MockedStatic<SystemSchemaUtils> mockedStatic = 
mockStatic(SystemSchemaUtils.class)) {
+            mockedStatic.when(() -> 
SystemSchemaUtils.isSystemSchema(systemDatabase)).thenReturn(true);
+            executor.executeUpdate(new RefreshDatabaseMetaDataStatement(null, 
false), contextManager);
+            verify(contextManager).reloadDatabase(normalDatabase);
+        }
+    }
+}
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/refresh/RefreshTableMetaDataExecutorTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/refresh/RefreshTableMetaDataExecutorTest.java
new file mode 100644
index 00000000000..1ad17bc115c
--- /dev/null
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/refresh/RefreshTableMetaDataExecutorTest.java
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package 
org.apache.shardingsphere.proxy.backend.handler.distsql.ral.updatable.refresh;
+
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.schema.DialectSchemaOption;
+import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import 
org.apache.shardingsphere.distsql.handler.engine.update.DistSQLUpdateExecutor;
+import 
org.apache.shardingsphere.distsql.statement.type.ral.updatable.RefreshTableMetaDataStatement;
+import 
org.apache.shardingsphere.infra.exception.kernel.metadata.SchemaNotFoundException;
+import 
org.apache.shardingsphere.infra.exception.kernel.metadata.TableNotFoundException;
+import 
org.apache.shardingsphere.infra.exception.kernel.metadata.resource.storageunit.EmptyStorageUnitException;
+import 
org.apache.shardingsphere.infra.exception.kernel.metadata.resource.storageunit.MissingRequiredStorageUnitsException;
+import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
+import 
org.apache.shardingsphere.infra.metadata.database.resource.ResourceMetaData;
+import 
org.apache.shardingsphere.infra.metadata.database.resource.unit.StorageUnit;
+import 
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.mode.manager.ContextManager;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class RefreshTableMetaDataExecutorTest {
+    
+    private final DatabaseType databaseType = mock(DatabaseType.class);
+    
+    private final RefreshTableMetaDataExecutor executor = 
(RefreshTableMetaDataExecutor) 
TypedSPILoader.getService(DistSQLUpdateExecutor.class, 
RefreshTableMetaDataStatement.class);
+    
+    @Test
+    void assertExecuteUpdateWithReloadTableWithStorageUnit() {
+        ShardingSphereDatabase database = mockDatabase(true);
+        ShardingSphereSchema schema = mock(ShardingSphereSchema.class);
+        when(schema.containsTable("t_order")).thenReturn(true);
+        when(database.getSchema("logic_schema")).thenReturn(schema);
+        ContextManager contextManager = mock(ContextManager.class);
+        executor.setDatabase(database);
+        executor.executeUpdate(new RefreshTableMetaDataStatement("t_order", 
"ds_0", "logic_schema"), contextManager);
+        verify(contextManager).reloadTable(database, "logic_schema", "ds_0", 
"t_order");
+    }
+    
+    @Test
+    void assertExecuteUpdateWithReloadSchemaWithStorageUnit() {
+        RefreshTableMetaDataStatement sqlStatement = new 
RefreshTableMetaDataStatement(null, "ds_0", "logic_schema");
+        ShardingSphereDatabase database = mockDatabase(true);
+        ContextManager contextManager = mock(ContextManager.class);
+        executor.setDatabase(database);
+        executor.executeUpdate(sqlStatement, contextManager);
+        verify(contextManager).reloadSchema(database, "logic_schema", "ds_0");
+    }
+    
+    @Test
+    void assertExecuteUpdateWithReloadTableWithoutStorageUnit() {
+        RefreshTableMetaDataStatement sqlStatement = new 
RefreshTableMetaDataStatement("t_order", null, null);
+        ShardingSphereDatabase database = mockDatabase(true);
+        when(database.getProtocolType()).thenReturn(databaseType);
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData();
+        ShardingSphereSchema schema = mock(ShardingSphereSchema.class);
+        when(schema.containsTable("t_order")).thenReturn(true);
+        when(database.getSchema("public")).thenReturn(schema);
+        ContextManager contextManager = mock(ContextManager.class);
+        executor.setDatabase(database);
+        try (MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            executor.executeUpdate(sqlStatement, contextManager);
+        }
+        verify(contextManager).reloadTable(database, "public", "t_order");
+    }
+    
+    @Test
+    void assertExecuteUpdateWithReloadDatabase() {
+        RefreshTableMetaDataStatement sqlStatement = new 
RefreshTableMetaDataStatement(null, null, null);
+        ShardingSphereDatabase database = mockDatabase(true);
+        when(database.getProtocolType()).thenReturn(databaseType);
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData();
+        ContextManager contextManager = mock(ContextManager.class);
+        executor.setDatabase(database);
+        try (MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            executor.executeUpdate(sqlStatement, contextManager);
+        }
+        verify(contextManager).reloadDatabase(database);
+    }
+    
+    @Test
+    void assertExecuteUpdateWithEmptyStorageUnits() {
+        RefreshTableMetaDataStatement sqlStatement = new 
RefreshTableMetaDataStatement(null, null, null);
+        ShardingSphereDatabase database = mock(ShardingSphereDatabase.class);
+        when(database.getName()).thenReturn("logic_db");
+        when(database.getProtocolType()).thenReturn(databaseType);
+        ResourceMetaData resourceMetaData = mock(ResourceMetaData.class);
+        when(database.getResourceMetaData()).thenReturn(resourceMetaData);
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData();
+        executor.setDatabase(database);
+        try (MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            assertThrows(EmptyStorageUnitException.class, () -> 
executor.executeUpdate(sqlStatement, mock(ContextManager.class)));
+        }
+    }
+    
+    @Test
+    void assertExecuteUpdateWithMissingStorageUnit() {
+        RefreshTableMetaDataStatement sqlStatement = new 
RefreshTableMetaDataStatement(null, "miss_ds", null);
+        ShardingSphereDatabase database = mockDatabase(true);
+        when(database.getProtocolType()).thenReturn(databaseType);
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData();
+        executor.setDatabase(database);
+        try (MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            assertThrows(MissingRequiredStorageUnitsException.class, () -> 
executor.executeUpdate(sqlStatement, mock(ContextManager.class)));
+        }
+    }
+    
+    @Test
+    void assertThrowWhenSchemaMissing() {
+        RefreshTableMetaDataStatement sqlStatement = new 
RefreshTableMetaDataStatement(null, null, "absent_schema");
+        ShardingSphereDatabase database = mockDatabase(false);
+        executor.setDatabase(database);
+        assertThrows(SchemaNotFoundException.class, () -> 
executor.executeUpdate(sqlStatement, mock(ContextManager.class)));
+    }
+    
+    @Test
+    void assertThrowWhenTableMissing() {
+        ShardingSphereDatabase database = mockDatabase(true);
+        ShardingSphereSchema schema = mock(ShardingSphereSchema.class);
+        when(schema.containsTable("missing_table")).thenReturn(false);
+        when(database.getSchema("logic_schema")).thenReturn(schema);
+        executor.setDatabase(database);
+        assertThrows(TableNotFoundException.class, () -> 
executor.executeUpdate(new RefreshTableMetaDataStatement("missing_table", null, 
"logic_schema"), mock(ContextManager.class)));
+    }
+    
+    private ShardingSphereDatabase mockDatabase(final boolean schemaExists) {
+        ShardingSphereDatabase result = mock(ShardingSphereDatabase.class, 
RETURNS_DEEP_STUBS);
+        when(result.getName()).thenReturn("logic_db");
+        
when(result.getResourceMetaData().getStorageUnits()).thenReturn(Collections.singletonMap("ds_0",
 mock(StorageUnit.class)));
+        when(result.containsSchema(anyString())).thenReturn(schemaExists);
+        return result;
+    }
+    
+    private DialectDatabaseMetaData mockDialectDatabaseMetaData() {
+        DialectDatabaseMetaData result = mock(DialectDatabaseMetaData.class);
+        DialectSchemaOption schemaOption = mock(DialectSchemaOption.class);
+        
when(schemaOption.getDefaultSchema()).thenReturn(Optional.of("public"));
+        when(result.getSchemaOption()).thenReturn(schemaOption);
+        return result;
+    }
+}
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/BeginTransactionProxyBackendHandlerTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/BeginTransactionProxyBackendHandlerTest.java
new file mode 100644
index 00000000000..f4320648697
--- /dev/null
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/BeginTransactionProxyBackendHandlerTest.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.proxy.backend.handler.tcl.local.type;
+
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.schema.DialectSchemaOption;
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.transaction.DialectTransactionOption;
+import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import 
org.apache.shardingsphere.database.exception.core.exception.transaction.InTransactionException;
+import 
org.apache.shardingsphere.proxy.backend.connector.ProxyDatabaseConnectionManager;
+import 
org.apache.shardingsphere.proxy.backend.connector.jdbc.transaction.ProxyBackendTransactionManager;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import 
org.apache.shardingsphere.proxy.backend.session.transaction.TransactionStatus;
+import 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.tcl.TCLStatement;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class BeginTransactionProxyBackendHandlerTest {
+    
+    private final DatabaseType databaseType = mock(DatabaseType.class);
+    
+    @Test
+    void assertBeginWhenNotInTransaction() throws SQLException {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData(false, "public");
+        TransactionStatus transactionStatus = new TransactionStatus();
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+        
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+        try (
+                MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class);
+                MockedConstruction<ProxyBackendTransactionManager> 
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            new BeginTransactionProxyBackendHandler(mock(TCLStatement.class), 
connectionSession).execute();
+            ProxyBackendTransactionManager transactionManager = 
mockedConstruction.constructed().get(0);
+            verify(transactionManager).begin();
+            verify(transactionManager, never()).commit();
+        }
+    }
+    
+    @Test
+    void assertBeginWithNestedTransactionCommit() throws SQLException {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData(true, "public");
+        TransactionStatus transactionStatus = new TransactionStatus();
+        transactionStatus.setInTransaction(true);
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+        try (
+                MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class);
+                MockedConstruction<ProxyBackendTransactionManager> 
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            new BeginTransactionProxyBackendHandler(mock(TCLStatement.class), 
connectionSession).execute();
+            ProxyBackendTransactionManager transactionManager = 
mockedConstruction.constructed().get(0);
+            verify(transactionManager).commit();
+            verify(transactionManager).begin();
+        }
+    }
+    
+    @Test
+    void assertThrowWhenNestedTransactionUnsupportedWithDefaultSchema() {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData(false, "public");
+        TransactionStatus transactionStatus = new TransactionStatus();
+        transactionStatus.setInTransaction(true);
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+        try (
+                MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class);
+                MockedConstruction<ProxyBackendTransactionManager> ignored = 
mockConstruction(ProxyBackendTransactionManager.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            assertThrows(InTransactionException.class, () -> new 
BeginTransactionProxyBackendHandler(mock(TCLStatement.class), 
connectionSession).execute());
+        }
+    }
+    
+    @Test
+    void assertBeginWhenDefaultSchemaNotPresent() throws SQLException {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData(false, null);
+        TransactionStatus transactionStatus = new TransactionStatus();
+        transactionStatus.setInTransaction(true);
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+        try (
+                MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class);
+                MockedConstruction<ProxyBackendTransactionManager> 
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            new BeginTransactionProxyBackendHandler(mock(TCLStatement.class), 
connectionSession).execute();
+            ProxyBackendTransactionManager transactionManager = 
mockedConstruction.constructed().get(0);
+            verify(transactionManager, never()).commit();
+            verify(transactionManager).begin();
+        }
+    }
+    
+    private DialectDatabaseMetaData mockDialectDatabaseMetaData(final boolean 
supportAutoCommitInNestedTransaction, final String defaultSchema) {
+        DialectDatabaseMetaData result = mock(DialectDatabaseMetaData.class);
+        DialectTransactionOption transactionOption = new 
DialectTransactionOption(false, false, supportAutoCommitInNestedTransaction, 
false, true,
+                Connection.TRANSACTION_READ_COMMITTED, false, false, 
Collections.emptyList());
+        DialectSchemaOption schemaOption = mock(DialectSchemaOption.class);
+        
when(schemaOption.getDefaultSchema()).thenReturn(Optional.ofNullable(defaultSchema));
+        when(result.getTransactionOption()).thenReturn(transactionOption);
+        when(result.getSchemaOption()).thenReturn(schemaOption);
+        return result;
+    }
+}
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/CommitProxyBackendHandlerTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/CommitProxyBackendHandlerTest.java
new file mode 100644
index 00000000000..fc4b946407c
--- /dev/null
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/CommitProxyBackendHandlerTest.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.proxy.backend.handler.tcl.local.type;
+
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.transaction.DialectTransactionOption;
+import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import org.apache.shardingsphere.infra.session.connection.ConnectionContext;
+import 
org.apache.shardingsphere.proxy.backend.connector.ProxyDatabaseConnectionManager;
+import 
org.apache.shardingsphere.proxy.backend.connector.jdbc.transaction.ProxyBackendTransactionManager;
+import org.apache.shardingsphere.proxy.backend.response.header.ResponseHeader;
+import 
org.apache.shardingsphere.proxy.backend.response.header.update.UpdateResponseHeader;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.tcl.RollbackStatement;
+import 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.tcl.TCLStatement;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Collections;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class CommitProxyBackendHandlerTest {
+    
+    private final DatabaseType databaseType = mock(DatabaseType.class);
+    
+    @Test
+    void assertReturnRollbackStatementWhenCommitFailed() throws SQLException {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData(true);
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        ConnectionContext connectionContext = new 
ConnectionContext(Collections::emptyList);
+        connectionContext.getTransactionContext().setExceptionOccur(true);
+        
when(connectionSession.getConnectionContext()).thenReturn(connectionContext);
+        
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+        TCLStatement sqlStatement = mock(TCLStatement.class);
+        try (
+                MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class);
+                MockedConstruction<ProxyBackendTransactionManager> 
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            ResponseHeader actual = new 
CommitProxyBackendHandler(sqlStatement, connectionSession).execute();
+            ProxyBackendTransactionManager transactionManager = 
mockedConstruction.constructed().get(0);
+            verify(transactionManager).commit();
+            assertThat(((UpdateResponseHeader) actual).getSqlStatement(), 
instanceOf(RollbackStatement.class));
+        }
+    }
+    
+    @Test
+    void assertReturnOriginalStatementWhenNoException() throws SQLException {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData(false);
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        ConnectionContext connectionContext = new 
ConnectionContext(Collections::emptyList);
+        
when(connectionSession.getConnectionContext()).thenReturn(connectionContext);
+        
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+        TCLStatement sqlStatement = mock(TCLStatement.class);
+        try (
+                MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class);
+                MockedConstruction<ProxyBackendTransactionManager> 
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            ResponseHeader actual = new 
CommitProxyBackendHandler(sqlStatement, connectionSession).execute();
+            ProxyBackendTransactionManager transactionManager = 
mockedConstruction.constructed().get(0);
+            verify(transactionManager).commit();
+            assertThat(((UpdateResponseHeader) actual).getSqlStatement(), 
is(sqlStatement));
+        }
+    }
+    
+    private DialectDatabaseMetaData mockDialectDatabaseMetaData(final boolean 
returnRollbackWhenFailed) {
+        DialectDatabaseMetaData result = mock(DialectDatabaseMetaData.class);
+        when(result.getTransactionOption()).thenReturn(new 
DialectTransactionOption(
+                false, false, false, false, true, 
Connection.TRANSACTION_READ_COMMITTED, returnRollbackWhenFailed, false, 
Collections.emptyList()));
+        return result;
+    }
+}
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/ReleaseSavepointProxyBackendHandlerTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/ReleaseSavepointProxyBackendHandlerTest.java
new file mode 100644
index 00000000000..285be3c677b
--- /dev/null
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/ReleaseSavepointProxyBackendHandlerTest.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.proxy.backend.handler.tcl.local.type;
+
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.schema.DialectSchemaOption;
+import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import 
org.apache.shardingsphere.proxy.backend.connector.ProxyDatabaseConnectionManager;
+import 
org.apache.shardingsphere.proxy.backend.connector.jdbc.transaction.ProxyBackendTransactionManager;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import 
org.apache.shardingsphere.proxy.backend.session.transaction.TransactionStatus;
+import 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.tcl.ReleaseSavepointStatement;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
+
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class ReleaseSavepointProxyBackendHandlerTest {
+    
+    private final DatabaseType databaseType = mock(DatabaseType.class);
+    
+    @Test
+    void assertReleaseSavepoint() throws SQLException {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData("public");
+        TransactionStatus transactionStatus = new TransactionStatus();
+        transactionStatus.setInTransaction(true);
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+        ReleaseSavepointStatement sqlStatement = 
mock(ReleaseSavepointStatement.class);
+        when(sqlStatement.getSavepointName()).thenReturn("sp_release");
+        try (
+                MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class);
+                MockedConstruction<ProxyBackendTransactionManager> 
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            new ReleaseSavepointProxyBackendHandler(sqlStatement, 
connectionSession).execute();
+            ProxyBackendTransactionManager transactionManager = 
mockedConstruction.constructed().get(0);
+            verify(transactionManager).releaseSavepoint("sp_release");
+        }
+    }
+    
+    @Test
+    void assertReleaseWithDefaultSchemaMissing() throws SQLException {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData(null);
+        TransactionStatus transactionStatus = new TransactionStatus();
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+        ReleaseSavepointStatement sqlStatement = 
mock(ReleaseSavepointStatement.class);
+        when(sqlStatement.getSavepointName()).thenReturn("sp_release");
+        try (
+                MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class);
+                MockedConstruction<ProxyBackendTransactionManager> 
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            new ReleaseSavepointProxyBackendHandler(sqlStatement, 
connectionSession).execute();
+            ProxyBackendTransactionManager transactionManager = 
mockedConstruction.constructed().get(0);
+            verify(transactionManager).releaseSavepoint("sp_release");
+        }
+    }
+    
+    @Test
+    void assertReleaseWithInvalidStatus() {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData("public");
+        TransactionStatus transactionStatus = new TransactionStatus();
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+        ReleaseSavepointStatement sqlStatement = 
mock(ReleaseSavepointStatement.class);
+        when(sqlStatement.getSavepointName()).thenReturn("sp_release");
+        try (
+                MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class);
+                MockedConstruction<ProxyBackendTransactionManager> ignored = 
mockConstruction(ProxyBackendTransactionManager.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            assertThrows(SQLFeatureNotSupportedException.class, () -> new 
ReleaseSavepointProxyBackendHandler(sqlStatement, connectionSession).execute());
+        }
+    }
+    
+    private DialectDatabaseMetaData mockDialectDatabaseMetaData(final String 
defaultSchema) {
+        DialectDatabaseMetaData result = mock(DialectDatabaseMetaData.class);
+        DialectSchemaOption schemaOption = mock(DialectSchemaOption.class);
+        
when(schemaOption.getDefaultSchema()).thenReturn(Optional.ofNullable(defaultSchema));
+        when(result.getSchemaOption()).thenReturn(schemaOption);
+        return result;
+    }
+}
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/RollbackSavepointProxyBackendHandlerTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/RollbackSavepointProxyBackendHandlerTest.java
new file mode 100644
index 00000000000..768accb279e
--- /dev/null
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/RollbackSavepointProxyBackendHandlerTest.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.proxy.backend.handler.tcl.local.type;
+
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.schema.DialectSchemaOption;
+import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import 
org.apache.shardingsphere.proxy.backend.connector.ProxyDatabaseConnectionManager;
+import 
org.apache.shardingsphere.proxy.backend.connector.jdbc.transaction.ProxyBackendTransactionManager;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import 
org.apache.shardingsphere.proxy.backend.session.transaction.TransactionStatus;
+import 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.tcl.RollbackStatement;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
+
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class RollbackSavepointProxyBackendHandlerTest {
+    
+    private final DatabaseType databaseType = mock(DatabaseType.class);
+    
+    @Test
+    void assertRollbackToSavepoint() throws SQLException {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData("public");
+        TransactionStatus transactionStatus = new TransactionStatus();
+        transactionStatus.setInTransaction(true);
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+        RollbackStatement sqlStatement = mock(RollbackStatement.class);
+        when(sqlStatement.getSavepointName()).thenReturn(Optional.of("sp1"));
+        try (
+                MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class);
+                MockedConstruction<ProxyBackendTransactionManager> 
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            new RollbackSavepointProxyBackendHandler(sqlStatement, 
connectionSession).execute();
+            ProxyBackendTransactionManager transactionManager = 
mockedConstruction.constructed().get(0);
+            verify(transactionManager).rollbackTo("sp1");
+        }
+    }
+    
+    @Test
+    void assertRollbackWithEmptySavepointName() throws SQLException {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData(null);
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        when(connectionSession.getTransactionStatus()).thenReturn(new 
TransactionStatus());
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+        RollbackStatement sqlStatement = mock(RollbackStatement.class);
+        when(sqlStatement.getSavepointName()).thenReturn(Optional.empty());
+        try (
+                MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class);
+                MockedConstruction<ProxyBackendTransactionManager> 
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            new RollbackSavepointProxyBackendHandler(sqlStatement, 
connectionSession).execute();
+            ProxyBackendTransactionManager transactionManager = 
mockedConstruction.constructed().get(0);
+            verify(transactionManager).rollbackTo("");
+        }
+    }
+    
+    @Test
+    void assertExecuteWithInvalidStatus() {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData("public");
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        when(connectionSession.getTransactionStatus()).thenReturn(new 
TransactionStatus());
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+        RollbackStatement sqlStatement = mock(RollbackStatement.class);
+        try (
+                MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class);
+                MockedConstruction<ProxyBackendTransactionManager> ignored = 
mockConstruction(ProxyBackendTransactionManager.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            assertThrows(SQLFeatureNotSupportedException.class, () -> new 
RollbackSavepointProxyBackendHandler(sqlStatement, 
connectionSession).execute());
+        }
+    }
+    
+    private DialectDatabaseMetaData mockDialectDatabaseMetaData(final String 
defaultSchema) {
+        DialectDatabaseMetaData result = mock(DialectDatabaseMetaData.class);
+        DialectSchemaOption schemaOption = mock(DialectSchemaOption.class);
+        
when(schemaOption.getDefaultSchema()).thenReturn(Optional.ofNullable(defaultSchema));
+        when(result.getSchemaOption()).thenReturn(schemaOption);
+        return result;
+    }
+}
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/SetAutoCommitProxyBackendHandlerTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/SetAutoCommitProxyBackendHandlerTest.java
new file mode 100644
index 00000000000..76ece8bfe4a
--- /dev/null
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/SetAutoCommitProxyBackendHandlerTest.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.proxy.backend.handler.tcl.local.type;
+
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.transaction.DialectTransactionOption;
+import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import 
org.apache.shardingsphere.proxy.backend.connector.ProxyDatabaseConnectionManager;
+import 
org.apache.shardingsphere.proxy.backend.connector.jdbc.transaction.ProxyBackendTransactionManager;
+import org.apache.shardingsphere.proxy.backend.response.header.ResponseHeader;
+import 
org.apache.shardingsphere.proxy.backend.response.header.update.UpdateResponseHeader;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import 
org.apache.shardingsphere.proxy.backend.session.transaction.TransactionStatus;
+import 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.tcl.SetAutoCommitStatement;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Collections;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class SetAutoCommitProxyBackendHandlerTest {
+    
+    private final DatabaseType databaseType = mock(DatabaseType.class);
+    
+    @Test
+    void assertExecuteCommitWhenNestedTransactionSupported() throws 
SQLException {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData(true);
+        TransactionStatus transactionStatus = new TransactionStatus();
+        transactionStatus.setInTransaction(true);
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+        SetAutoCommitStatement sqlStatement = 
mock(SetAutoCommitStatement.class);
+        when(sqlStatement.isAutoCommit()).thenReturn(true);
+        try (
+                MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class);
+                MockedConstruction<ProxyBackendTransactionManager> 
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            ResponseHeader actual = new 
SetAutoCommitProxyBackendHandler(sqlStatement, connectionSession).execute();
+            ProxyBackendTransactionManager transactionManager = 
mockedConstruction.constructed().get(0);
+            verify(transactionManager).commit();
+            verify(connectionSession).setAutoCommit(true);
+            assertThat(((UpdateResponseHeader) actual).getSqlStatement(), 
is(sqlStatement));
+        }
+    }
+    
+    @Test
+    void assertExecuteWithoutCommitWhenNestedTransactionUnsupported() throws 
SQLException {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData(false);
+        TransactionStatus transactionStatus = new TransactionStatus();
+        transactionStatus.setInTransaction(true);
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+        SetAutoCommitStatement sqlStatement = 
mock(SetAutoCommitStatement.class);
+        when(sqlStatement.isAutoCommit()).thenReturn(true);
+        try (
+                MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class);
+                MockedConstruction<ProxyBackendTransactionManager> 
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            assertDoesNotThrow(() -> new 
SetAutoCommitProxyBackendHandler(sqlStatement, connectionSession).execute());
+            ProxyBackendTransactionManager transactionManager = 
mockedConstruction.constructed().get(0);
+            verify(connectionSession).setAutoCommit(true);
+            verify(transactionManager, never()).commit();
+        }
+    }
+    
+    @Test
+    void assertExecuteWhenAutoCommitDisabled() throws SQLException {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData(true);
+        TransactionStatus transactionStatus = new TransactionStatus();
+        transactionStatus.setInTransaction(true);
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+        SetAutoCommitStatement sqlStatement = 
mock(SetAutoCommitStatement.class);
+        when(sqlStatement.isAutoCommit()).thenReturn(false);
+        try (
+                MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class);
+                MockedConstruction<ProxyBackendTransactionManager> 
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            new SetAutoCommitProxyBackendHandler(sqlStatement, 
connectionSession).execute();
+            ProxyBackendTransactionManager transactionManager = 
mockedConstruction.constructed().get(0);
+            verify(transactionManager, never()).commit();
+            verify(connectionSession).setAutoCommit(false);
+        }
+    }
+    
+    @Test
+    void assertExecuteWhenNotInTransaction() throws SQLException {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData(true);
+        TransactionStatus transactionStatus = new TransactionStatus();
+        transactionStatus.setInTransaction(false);
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+        SetAutoCommitStatement sqlStatement = 
mock(SetAutoCommitStatement.class);
+        when(sqlStatement.isAutoCommit()).thenReturn(true);
+        try (
+                MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class);
+                MockedConstruction<ProxyBackendTransactionManager> 
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            new SetAutoCommitProxyBackendHandler(sqlStatement, 
connectionSession).execute();
+            ProxyBackendTransactionManager transactionManager = 
mockedConstruction.constructed().get(0);
+            verify(transactionManager, never()).commit();
+            verify(connectionSession).setAutoCommit(true);
+        }
+    }
+    
+    private DialectDatabaseMetaData mockDialectDatabaseMetaData(final boolean 
supportAutoCommitInNestedTransaction) {
+        DialectDatabaseMetaData result = mock(DialectDatabaseMetaData.class);
+        DialectTransactionOption transactionOption = new 
DialectTransactionOption(false, false, supportAutoCommitInNestedTransaction, 
false, true,
+                Connection.TRANSACTION_READ_COMMITTED, false, false, 
Collections.emptyList());
+        when(result.getTransactionOption()).thenReturn(transactionOption);
+        return result;
+    }
+}
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/SetSavepointProxyBackendHandlerTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/SetSavepointProxyBackendHandlerTest.java
new file mode 100644
index 00000000000..ae8484dadd4
--- /dev/null
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/SetSavepointProxyBackendHandlerTest.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.proxy.backend.handler.tcl.local.type;
+
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.schema.DialectSchemaOption;
+import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import 
org.apache.shardingsphere.proxy.backend.connector.ProxyDatabaseConnectionManager;
+import 
org.apache.shardingsphere.proxy.backend.connector.jdbc.transaction.ProxyBackendTransactionManager;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import 
org.apache.shardingsphere.proxy.backend.session.transaction.TransactionStatus;
+import 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.tcl.SavepointStatement;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
+
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class SetSavepointProxyBackendHandlerTest {
+    
+    private final DatabaseType databaseType = mock(DatabaseType.class);
+    
+    @Test
+    void assertExecuteWithTransaction() throws SQLException {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData("public");
+        TransactionStatus transactionStatus = new TransactionStatus();
+        transactionStatus.setInTransaction(true);
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+        SavepointStatement sqlStatement = mock(SavepointStatement.class);
+        when(sqlStatement.getSavepointName()).thenReturn("foo_point");
+        try (
+                MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class);
+                MockedConstruction<ProxyBackendTransactionManager> 
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            new SetSavepointProxyBackendHandler(sqlStatement, 
connectionSession).execute();
+            ProxyBackendTransactionManager transactionManager = 
mockedConstruction.constructed().get(0);
+            verify(transactionManager).setSavepoint("foo_point");
+        }
+    }
+    
+    @Test
+    void assertExecuteWithoutTransactionButNoDefaultSchema() throws 
SQLException {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData(null);
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        when(connectionSession.getTransactionStatus()).thenReturn(new 
TransactionStatus());
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+        SavepointStatement sqlStatement = mock(SavepointStatement.class);
+        when(sqlStatement.getSavepointName()).thenReturn("bar_point");
+        try (
+                MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class);
+                MockedConstruction<ProxyBackendTransactionManager> 
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            new SetSavepointProxyBackendHandler(sqlStatement, 
connectionSession).execute();
+            ProxyBackendTransactionManager transactionManager = 
mockedConstruction.constructed().get(0);
+            verify(transactionManager).setSavepoint("bar_point");
+        }
+    }
+    
+    @Test
+    void assertExecuteWithInvalidStatus() {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData("public");
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        when(connectionSession.getTransactionStatus()).thenReturn(new 
TransactionStatus());
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+        SavepointStatement sqlStatement = mock(SavepointStatement.class);
+        try (
+                MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class);
+                MockedConstruction<ProxyBackendTransactionManager> ignored = 
mockConstruction(ProxyBackendTransactionManager.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            assertThrows(SQLFeatureNotSupportedException.class, () -> new 
SetSavepointProxyBackendHandler(sqlStatement, connectionSession).execute());
+        }
+    }
+    
+    private DialectDatabaseMetaData mockDialectDatabaseMetaData(final String 
defaultSchema) {
+        DialectDatabaseMetaData result = mock(DialectDatabaseMetaData.class);
+        DialectSchemaOption schemaOption = mock(DialectSchemaOption.class);
+        
when(schemaOption.getDefaultSchema()).thenReturn(Optional.ofNullable(defaultSchema));
+        when(result.getSchemaOption()).thenReturn(schemaOption);
+        return result;
+    }
+}
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/SetTransactionProxyBackendHandlerTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/SetTransactionProxyBackendHandlerTest.java
new file mode 100644
index 00000000000..6635da40e4d
--- /dev/null
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/SetTransactionProxyBackendHandlerTest.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.proxy.backend.handler.tcl.local.type;
+
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.transaction.DialectTransactionOption;
+import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import 
org.apache.shardingsphere.proxy.backend.response.header.update.UpdateResponseHeader;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import 
org.apache.shardingsphere.proxy.backend.session.transaction.TransactionStatus;
+import 
org.apache.shardingsphere.sql.parser.statement.core.enums.TransactionAccessType;
+import 
org.apache.shardingsphere.sql.parser.statement.core.enums.TransactionIsolationLevel;
+import 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.tcl.SetTransactionStatement;
+import 
org.apache.shardingsphere.transaction.exception.SwitchTypeInTransactionException;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+
+import java.sql.Connection;
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class SetTransactionProxyBackendHandlerTest {
+    
+    private final DatabaseType databaseType = mock(DatabaseType.class);
+    
+    @Test
+    void assertExecuteWhenSwitchTypeInTransaction() {
+        TransactionStatus transactionStatus = new TransactionStatus();
+        transactionStatus.setInTransaction(true);
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        SetTransactionStatement sqlStatement = 
mock(SetTransactionStatement.class);
+        when(sqlStatement.containsScope()).thenReturn(false);
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData(Connection.TRANSACTION_READ_COMMITTED);
+        try (MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            assertThrows(SwitchTypeInTransactionException.class, () -> new 
SetTransactionProxyBackendHandler(sqlStatement, connectionSession).execute());
+        }
+    }
+    
+    @Test
+    void assertExecuteWhenSetReadOnly() {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData(Connection.TRANSACTION_READ_COMMITTED);
+        TransactionStatus transactionStatus = new TransactionStatus();
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        SetTransactionStatement sqlStatement = 
mock(SetTransactionStatement.class);
+        when(sqlStatement.containsScope()).thenReturn(true);
+        
when(sqlStatement.isDesiredAccessMode(TransactionAccessType.READ_ONLY)).thenReturn(true);
+        when(sqlStatement.getIsolationLevel()).thenReturn(Optional.empty());
+        try (MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            UpdateResponseHeader actual = (UpdateResponseHeader) new 
SetTransactionProxyBackendHandler(sqlStatement, connectionSession).execute();
+            verify(connectionSession).setReadOnly(true);
+            assertThat(actual.getSqlStatement(), is(sqlStatement));
+        }
+    }
+    
+    @Test
+    void assertExecuteWhenSetReadWrite() {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData(Connection.TRANSACTION_READ_COMMITTED);
+        TransactionStatus transactionStatus = new TransactionStatus();
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        SetTransactionStatement sqlStatement = 
mock(SetTransactionStatement.class);
+        when(sqlStatement.containsScope()).thenReturn(true);
+        
when(sqlStatement.isDesiredAccessMode(TransactionAccessType.READ_WRITE)).thenReturn(true);
+        when(sqlStatement.getIsolationLevel()).thenReturn(Optional.empty());
+        try (MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            new SetTransactionProxyBackendHandler(sqlStatement, 
connectionSession).execute();
+            verify(connectionSession).setReadOnly(false);
+        }
+    }
+    
+    @Test
+    void assertExecuteWhenSetIsolationLevel() {
+        DialectDatabaseMetaData dialectDatabaseMetaData = 
mockDialectDatabaseMetaData(Connection.TRANSACTION_SERIALIZABLE);
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        when(connectionSession.getTransactionStatus()).thenReturn(new 
TransactionStatus());
+        when(connectionSession.getProtocolType()).thenReturn(databaseType);
+        SetTransactionStatement sqlStatement = 
mock(SetTransactionStatement.class);
+        when(sqlStatement.containsScope()).thenReturn(false);
+        
when(sqlStatement.isDesiredAccessMode(Mockito.any())).thenReturn(false);
+        
when(sqlStatement.getIsolationLevel()).thenReturn(Optional.of(TransactionIsolationLevel.SERIALIZABLE));
+        try (MockedStatic<DatabaseTypedSPILoader> mockedStatic = 
mockStatic(DatabaseTypedSPILoader.class)) {
+            mockedStatic.when(() -> 
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class, 
databaseType)).thenReturn(dialectDatabaseMetaData);
+            new SetTransactionProxyBackendHandler(sqlStatement, 
connectionSession).execute();
+            
verify(connectionSession).setDefaultIsolationLevel(TransactionIsolationLevel.SERIALIZABLE);
+            
verify(connectionSession).setIsolationLevel(TransactionIsolationLevel.SERIALIZABLE);
+        }
+    }
+    
+    private DialectDatabaseMetaData mockDialectDatabaseMetaData(final int 
defaultIsolationLevel) {
+        DialectDatabaseMetaData result = mock(DialectDatabaseMetaData.class);
+        DialectTransactionOption transactionOption = new 
DialectTransactionOption(false, false, false, false, true, 
defaultIsolationLevel, false, false, Collections.emptyList());
+        doReturn(transactionOption).when(result).getTransactionOption();
+        return result;
+    }
+}
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/impl/ReadOnlyProxyStateTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/type/ReadOnlyProxyStateCheckerTest.java
similarity index 50%
rename from 
proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/impl/ReadOnlyProxyStateTest.java
rename to 
proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/type/ReadOnlyProxyStateCheckerTest.java
index 7ff4df4eb04..3af3c640fbf 100644
--- 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/impl/ReadOnlyProxyStateTest.java
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/type/ReadOnlyProxyStateCheckerTest.java
@@ -15,26 +15,34 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.proxy.backend.state.impl;
+package org.apache.shardingsphere.proxy.backend.state.type;
 
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import 
org.apache.shardingsphere.distsql.statement.type.ral.updatable.UnlockClusterStatement;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 import org.apache.shardingsphere.mode.exception.ShardingSphereStateException;
-import 
org.apache.shardingsphere.proxy.backend.state.type.ReadOnlyProxyStateChecker;
+import org.apache.shardingsphere.mode.state.ShardingSphereState;
+import org.apache.shardingsphere.proxy.backend.state.ProxyClusterStateChecker;
 import 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.InsertStatement;
-import 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement;
 import org.junit.jupiter.api.Test;
 
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.Mockito.mock;
 
-class ReadOnlyProxyStateTest {
+class ReadOnlyProxyStateCheckerTest {
+    
+    private final DatabaseType databaseType = 
TypedSPILoader.getService(DatabaseType.class, "FIXTURE");
+    
+    private final ProxyClusterStateChecker stateChecker = 
TypedSPILoader.getService(ProxyClusterStateChecker.class, 
ShardingSphereState.READ_ONLY);
     
     @Test
-    void assertExecuteWithUnsupportedSQL() {
-        assertThrows(ShardingSphereStateException.class, () -> new 
ReadOnlyProxyStateChecker().check(mock(InsertStatement.class), mock()));
+    void assertCheckUnsupportedSQL() {
+        assertThrows(ShardingSphereStateException.class, () -> 
stateChecker.check(mock(InsertStatement.class), databaseType));
     }
     
     @Test
-    void assertExecuteWithSupportedSQL() {
-        new ReadOnlyProxyStateChecker().check(mock(SelectStatement.class), 
mock());
+    void assertCheckSupportedSQL() {
+        assertDoesNotThrow(() -> 
stateChecker.check(mock(UnlockClusterStatement.class), databaseType));
     }
 }
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/impl/UnavailableProxyStateTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/type/UnavailableProxyStateCheckerTest.java
similarity index 80%
rename from 
proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/impl/UnavailableProxyStateTest.java
rename to 
proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/type/UnavailableProxyStateCheckerTest.java
index 8c3769340d4..5055006342c 100644
--- 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/impl/UnavailableProxyStateTest.java
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/type/UnavailableProxyStateCheckerTest.java
@@ -15,15 +15,16 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.proxy.backend.state.impl;
+package org.apache.shardingsphere.proxy.backend.state.type;
 
 import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 import 
org.apache.shardingsphere.distsql.statement.type.ral.updatable.ImportMetaDataStatement;
 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 import org.apache.shardingsphere.mode.exception.ShardingSphereStateException;
+import org.apache.shardingsphere.mode.state.ShardingSphereState;
 import 
org.apache.shardingsphere.proxy.backend.state.DialectProxyStateSupportedSQLProvider;
-import 
org.apache.shardingsphere.proxy.backend.state.type.UnavailableProxyStateChecker;
+import org.apache.shardingsphere.proxy.backend.state.ProxyClusterStateChecker;
 import 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.DMLStatement;
 import 
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
 import 
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
@@ -40,20 +41,22 @@ import static org.mockito.Mockito.when;
 
 @ExtendWith(AutoMockExtension.class)
 @StaticMockSettings(DatabaseTypedSPILoader.class)
-class UnavailableProxyStateTest {
+class UnavailableProxyStateCheckerTest {
     
     private final DatabaseType databaseType = 
TypedSPILoader.getService(DatabaseType.class, "FIXTURE");
     
+    private final ProxyClusterStateChecker stateChecker = 
TypedSPILoader.getService(ProxyClusterStateChecker.class, 
ShardingSphereState.UNAVAILABLE);
+    
     @Test
     void assertExecuteWithUnsupportedSQL() {
         
when(DatabaseTypedSPILoader.findService(DialectProxyStateSupportedSQLProvider.class,
 databaseType)).thenReturn(Optional.empty());
-        assertThrows(ShardingSphereStateException.class, () -> new 
UnavailableProxyStateChecker().check(mock(DMLStatement.class), databaseType));
+        assertThrows(ShardingSphereStateException.class, () -> 
stateChecker.check(mock(DMLStatement.class), databaseType));
     }
     
     @Test
     void assertExecuteWithSupportedSQL() {
         
when(DatabaseTypedSPILoader.findService(DialectProxyStateSupportedSQLProvider.class,
 databaseType)).thenReturn(Optional.empty());
-        assertDoesNotThrow(() -> new 
UnavailableProxyStateChecker().check(mock(ImportMetaDataStatement.class), 
databaseType));
+        assertDoesNotThrow(() -> 
stateChecker.check(mock(ImportMetaDataStatement.class), databaseType));
     }
     
     @Test
@@ -61,6 +64,6 @@ class UnavailableProxyStateTest {
         DialectProxyStateSupportedSQLProvider supportedSQLProvider = 
mock(DialectProxyStateSupportedSQLProvider.class);
         
when(supportedSQLProvider.getSupportedSQLStatementTypesOnUnavailableState()).thenReturn(Collections.singleton(DMLStatement.class));
         
when(DatabaseTypedSPILoader.findService(DialectProxyStateSupportedSQLProvider.class,
 databaseType)).thenReturn(Optional.of(supportedSQLProvider));
-        assertDoesNotThrow(() -> new 
UnavailableProxyStateChecker().check(mock(DMLStatement.class), databaseType));
+        assertDoesNotThrow(() -> stateChecker.check(mock(DMLStatement.class), 
databaseType));
     }
 }
diff --git 
a/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/sysvar/provider/VersionValueProviderTest.java
 
b/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/sysvar/provider/VersionValueProviderTest.java
index b577306a53b..3473623438d 100644
--- 
a/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/sysvar/provider/VersionValueProviderTest.java
+++ 
b/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/sysvar/provider/VersionValueProviderTest.java
@@ -30,10 +30,10 @@ import 
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockS
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.MockedStatic;
-import org.mockito.Mockito;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.mockStatic;
 
 @ExtendWith(AutoMockExtension.class)
 @StaticMockSettings(ProxyContext.class)
@@ -42,7 +42,7 @@ class VersionValueProviderTest {
     @Test
     void assertGetValue() {
         DatabaseType databaseType = 
TypedSPILoader.getService(DatabaseType.class, "MySQL");
-        try (MockedStatic<DatabaseProtocolServerInfo> mockedStatic = 
Mockito.mockStatic(DatabaseProtocolServerInfo.class)) {
+        try (MockedStatic<DatabaseProtocolServerInfo> mockedStatic = 
mockStatic(DatabaseProtocolServerInfo.class)) {
             mockedStatic.when(() -> 
DatabaseProtocolServerInfo.getProtocolVersion(null, 
databaseType)).thenReturn("8.0");
             ConnectionSession connectionSession = new 
ConnectionSession(databaseType, new DefaultAttributeMap());
             assertThat(new 
VersionValueProvider().get(MySQLSystemVariableScope.GLOBAL, connectionSession, 
MySQLSystemVariable.VERSION), is("8.0"));

Reply via email to