This is an automated email from the ASF dual-hosted git repository.

Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new 40bd3cf74c fix: scope rule batch delete by namespace (#6987)
40bd3cf74c is described below

commit 40bd3cf74c8ef3745c6a00dc856ec71ecc564bc8
Author: Southern <[email protected]>
AuthorDate: Wed Aug 26 13:49:19 2026 +0800

    fix: scope rule batch delete by namespace (#6987)
    
    Add namespace-scoped mapper methods and SQL statements using:
      `id IN (...) AND namespace_id = #{namespaceId}`.
    
      Update RuleServiceImpl to:
      - query rules only within the requested namespace;
      - return 0 without side effects when no rules match;
      - delete only IDs returned by the scoped query;
      - delete rule conditions and publish events only for matched rules.
---
 .../org/apache/shenyu/admin/mapper/RuleMapper.java    | 18 ++++++++++++++++++
 .../shenyu/admin/service/impl/RuleServiceImpl.java    | 11 ++++++++---
 .../src/main/resources/mappers/rule-sqlmap.xml        | 19 +++++++++++++++++++
 .../apache/shenyu/admin/mapper/RuleMapperTest.java    | 19 +++++++++++++++++++
 .../apache/shenyu/admin/service/RuleServiceTest.java  | 16 ++++++++++++++--
 5 files changed, 78 insertions(+), 5 deletions(-)

diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/RuleMapper.java 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/RuleMapper.java
index 13ef28a98d..a018303773 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/RuleMapper.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/RuleMapper.java
@@ -147,6 +147,24 @@ public interface RuleMapper extends ExistProvider {
      */
     int deleteByIds(List<String> ids);
 
+    /**
+     * Select rules by ids and namespace id.
+     *
+     * @param ids primary keys
+     * @param namespaceId namespace id
+     * @return rule list
+     */
+    List<RuleDO> selectByIdsAndNamespaceId(@Param("ids") List<String> ids, 
@Param("namespaceId") String namespaceId);
+
+    /**
+     * Delete rules by ids and namespace id.
+     *
+     * @param ids primary keys
+     * @param namespaceId namespace id
+     * @return rows int
+     */
+    int deleteByIdsAndNamespaceId(@Param("ids") List<String> ids, 
@Param("namespaceId") String namespaceId);
+
     /**
      * list all.
      *
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/RuleServiceImpl.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/RuleServiceImpl.java
index 04eca5ccda..49855adc57 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/RuleServiceImpl.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/RuleServiceImpl.java
@@ -422,16 +422,21 @@ public class RuleServiceImpl implements RuleService {
      * delete rules by ids and namespaceId.
      *
      * @param ids primary key.
+     * @param namespaceId namespace id.
      * @return rows
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
     public int deleteByIdsAndNamespaceId(final List<String> ids, final String 
namespaceId) {
-        List<RuleDO> rules = ruleMapper.selectByIds(ids);
-        final int deleteCount = ruleMapper.deleteByIds(ids);
+        List<RuleDO> rules = ruleMapper.selectByIdsAndNamespaceId(ids, 
namespaceId);
+        if (CollectionUtils.isEmpty(rules)) {
+            return 0;
+        }
+        final List<String> ruleIds = map(rules, RuleDO::getId);
+        final int deleteCount = ruleMapper.deleteByIdsAndNamespaceId(ruleIds, 
namespaceId);
         if (deleteCount > 0) {
             ruleEventPublisher.onDeleted(rules);
-            ruleConditionMapper.deleteByRuleIds(ids);
+            ruleConditionMapper.deleteByRuleIds(ruleIds);
         }
         return deleteCount;
     }
diff --git a/shenyu-admin/src/main/resources/mappers/rule-sqlmap.xml 
b/shenyu-admin/src/main/resources/mappers/rule-sqlmap.xml
index 3c250a09eb..e9b86b24ec 100644
--- a/shenyu-admin/src/main/resources/mappers/rule-sqlmap.xml
+++ b/shenyu-admin/src/main/resources/mappers/rule-sqlmap.xml
@@ -209,6 +209,16 @@
         </foreach>
     </select>
 
+    <select id="selectByIdsAndNamespaceId" 
resultType="org.apache.shenyu.admin.model.entity.RuleDO">
+        select *
+        from rule
+        where id IN
+        <foreach item="id" collection="ids" open="(" separator="," close=")">
+            #{id, jdbcType=VARCHAR}
+        </foreach>
+        AND namespace_id = #{namespaceId, jdbcType=VARCHAR}
+    </select>
+
     <insert id="insert" 
parameterType="org.apache.shenyu.admin.model.entity.RuleDO">
         INSERT INTO rule (id,
                          date_created,
@@ -381,4 +391,13 @@
                         #{id, jdbcType=VARCHAR}
                     </foreach>
     </delete>
+
+    <delete id="deleteByIdsAndNamespaceId">
+        DELETE FROM rule
+              WHERE id IN
+                    <foreach item="id" collection="ids" open="(" separator="," 
close=")">
+                        #{id, jdbcType=VARCHAR}
+                    </foreach>
+              AND namespace_id = #{namespaceId, jdbcType=VARCHAR}
+    </delete>
 </mapper>
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/RuleMapperTest.java 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/RuleMapperTest.java
index 2a2938d359..340a6e8e7f 100644
--- 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/RuleMapperTest.java
+++ 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/RuleMapperTest.java
@@ -24,6 +24,8 @@ import org.apache.shenyu.common.utils.UUIDUtils;
 import org.junit.jupiter.api.Test;
 import jakarta.annotation.Resource;
 import java.sql.Timestamp;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Random;
 
@@ -190,6 +192,23 @@ public final class RuleMapperTest extends 
AbstractSpringIntegrationTest {
         assertThat(delete, equalTo(1));
     }
 
+    @Test
+    public void deleteByIdsAndNamespaceId() {
+        RuleDO ruleInNamespace = buildRuleDO();
+        RuleDO ruleInAnotherNamespace = buildRuleDO();
+        ruleInAnotherNamespace.setNamespaceId("another-namespace");
+        assertThat(ruleMapper.insert(ruleInNamespace), equalTo(1));
+        assertThat(ruleMapper.insert(ruleInAnotherNamespace), equalTo(1));
+
+        List<String> ids = Arrays.asList(ruleInNamespace.getId(), 
ruleInAnotherNamespace.getId());
+        assertThat(ruleMapper.selectByIdsAndNamespaceId(ids, 
SYS_DEFAULT_NAMESPACE_ID).size(), equalTo(1));
+        
assertThat(ruleMapper.selectByIdsAndNamespaceId(Collections.singletonList(ruleInAnotherNamespace.getId()),
 SYS_DEFAULT_NAMESPACE_ID).isEmpty(), equalTo(true));
+        assertThat(ruleMapper.deleteByIdsAndNamespaceId(ids, 
SYS_DEFAULT_NAMESPACE_ID), equalTo(1));
+        assertThat(ruleMapper.selectById(ruleInAnotherNamespace.getId()), 
equalTo(ruleInAnotherNamespace));
+
+        assertThat(ruleMapper.delete(ruleInAnotherNamespace.getId()), 
equalTo(1));
+    }
+
     private RuleDO buildRuleDO() {
         Timestamp now = new Timestamp(System.currentTimeMillis());
         String id = UUIDUtils.getInstance().generateShortUuid();
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/RuleServiceTest.java
 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/RuleServiceTest.java
index 2725ec84e5..d8fbb27e89 100644
--- 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/RuleServiceTest.java
+++ 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/RuleServiceTest.java
@@ -79,6 +79,8 @@ import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.BDDMockito.given;
 import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 /**
@@ -133,10 +135,20 @@ public final class RuleServiceTest {
     public void testDelete() {
         publishEvent();
         RuleDO ruleDO = buildRuleDO("123");
-        given(this.ruleMapper.selectById("123")).willReturn(ruleDO);
         final List<String> ids = Collections.singletonList(ruleDO.getId());
-        given(this.ruleMapper.deleteByIds(ids)).willReturn(ids.size());
+        given(this.ruleMapper.selectByIdsAndNamespaceId(ids, 
SYS_DEFAULT_NAMESPACE_ID)).willReturn(Collections.singletonList(ruleDO));
+        given(this.ruleMapper.deleteByIdsAndNamespaceId(ids, 
SYS_DEFAULT_NAMESPACE_ID)).willReturn(ids.size());
         assertEquals(this.ruleService.deleteByIdsAndNamespaceId(ids, 
SYS_DEFAULT_NAMESPACE_ID), ids.size());
+        verify(this.ruleConditionMapper).deleteByRuleIds(ids);
+    }
+
+    @Test
+    public void testDeleteWithNoRulesInNamespace() {
+        final List<String> ids = Collections.singletonList("123");
+        given(this.ruleMapper.selectByIdsAndNamespaceId(ids, 
SYS_DEFAULT_NAMESPACE_ID)).willReturn(Collections.emptyList());
+
+        assertEquals(this.ruleService.deleteByIdsAndNamespaceId(ids, 
SYS_DEFAULT_NAMESPACE_ID), 0);
+        verify(this.ruleMapper, never()).deleteByIdsAndNamespaceId(ids, 
SYS_DEFAULT_NAMESPACE_ID);
     }
 
     @Test

Reply via email to