当前位置: 首页 > article >正文

SQL写法技巧

目录

1.批量插入,查询,删除数据

缺点

实现方法

1.批量插入数据

2.批量查询数据

3.批量删除数据

4.批量修改数据

解释

2.树型表查询

方法一:递归(适用于多级的情况)

方法二:表的自连接

方法三:MySQL递归(既可以向下递归也可以向上递归)(MySQL8 支持)

表的连接该怎么选择

1.等值连接&内连接

2.左连接&右连接&外连接

3.自连接


1.批量插入,查询,删除数据

千万不要循环调用数据库!!!

比如:

public void deleteBatch(List<Integer> ids) {for (Integer id : ids) {blogMapper.deleteById(id);}
}
缺点
  1. 性能问题
    • 高延迟:每次数据库操作都需要建立连接、执行操作、然后关闭连接,这个过程涉及到网络延迟和数据库处理时间。
    • 资源消耗:频繁的数据库连接和断开操作会消耗大量的系统资源,如内存和CPU。
    • 并发限制:数据库连接通常是有限的资源,大量并发连接可能会导致数据库连接池耗尽。
  1. 可扩展性问题
    • 瓶颈:当需要处理大量数据时,循环调用数据库会成为一个明显的性能瓶颈。
    • 扩展难度:随着数据量的增加,系统的性能会显著下降,而优化这种循环操作通常比较困难。
  1. 事务管理
    • 事务开销:每次数据库操作可能都会启动一个新的事务,这会增加事务管理的开销。
    • 原子性保证困难:如果需要保证一系列操作的原子性,循环调用可能会导致部分操作成功而部分失败,难以实现原子性。
  1. 维护和调试困难
    • 代码复杂性:循环调用数据库的代码通常比较冗长且难以维护。
    • 错误追踪:如果其中一个操作失败,可能需要检查每个单独的操作来确定问题所在,增加了调试的难度。
  1. 锁竞争和死锁
    • 锁竞争:循环操作可能会导致数据库上的锁竞争,影响数据库的整体性能。
    • 死锁风险:如果多个线程或进程同时进行循环操作,可能会增加死锁的风险。
  1. 用户体验
    • 响应时间:用户可能会遇到较长的等待时间,特别是在前端需要等待所有数据库操作完成后才能继续执行的情况下。
实现方法
1.批量插入数据
public interface BlogMapper {// 假设Blog是一个实体类,代表要插入的数据int insertBatch(List<Blog> blogs);
}
public class BlogService {@Autowiredprivate BlogMapper blogMapper;public void insertBatch(List<Blog> blogs) {blogMapper.insertBatch(blogs);}
}
<!-- BlogMapper.xml -->
<insert id="insertBatch" parameterType="java.util.List">INSERT INTO blogs (column1, column2, ...)VALUES<foreach collection="list" item="blog" separator=",">(#{blog.column1}, #{blog.column2}, ...)</foreach>
</insert>
2.批量查询数据
public interface BlogMapper {// 假设Blog是一个实体类,代表查询结果List<Blog> selectBatch(List<Integer> ids);
}
public class BlogService {@Autowiredprivate BlogMapper blogMapper;public List<Blog> selectBatch(List<Integer> ids) {return blogMapper.selectBatch(ids);}
}
<!-- BlogMapper.xml -->
<select id="selectBatch" parameterType="java.util.List" resultType="Blog">SELECT * FROM blogs WHERE id IN<foreach item="id" collection="list" open="(" separator="," close=")">#{id}</foreach>
</select>
3.批量删除数据
public interface BlogMapper {int deleteBatch(List<Integer> ids);
}
public class BlogService {@Autowiredprivate BlogMapper blogMapper;public void deleteBatch(List<Integer> ids) {blogMapper.deleteBatch(ids);}
}
<!-- BlogMapper.xml -->
<delete id="deleteBatch" parameterType="java.util.List">DELETE FROM blogs WHERE id IN<foreach item="id" collection="list" open="(" separator="," close=")">#{id}</foreach>
</delete>
<delete id="deleteEnergyWorkshopByIds" parameterType="String">delete from energy_workshop where id in<foreach item="id" collection="array" open="(" separator="," close=")">#{id}</foreach>
</delete>
4.批量修改数据

举例 1:

<update id="changeSort"><foreach collection="videoSeriesList" separator=";" item="item">update user_video_seriesset sort = #{item.sort}where user_id = #{item.userId} and series_id = #{item.seriesId}</foreach>
</update>

举例 2:

void update(@Param("blogs") List<Blog> blogs);
<update id="update" parameterType="java.util.List">UPDATE blogSET read_count =<foreach collection="blogs" item="blog" separator=" "
open="CASE id" close="END">WHEN #{blog.id} THEN #{blog.readCount}</foreach>WHERE id IN<foreach collection="blogs" item="blog" separator=","
open="(" close=")">#{blog.id}</foreach>
</update>
以上sql拼接的结果类似于:
UPDATE blog
SET read_count = 
CASE idWHEN 1 THEN 10WHEN 2 THEN 20WHEN 3 THEN 30
END
WHERE id IN (1, 2, 3)
解释
  1. foreach 标签的作用foreach 标签用于遍历集合,并将集合中的每个元素插入到 SQL 语句中。它最终生成的是一条 SQL 语句,而不是多条 SQL 语句。
  2. IN 子句的实现:MyBatis 会将 foreach 标签生成的 SQL 语句发送到数据库,数据库会一次性处理这些查询操作,而不是逐条查询。这种方式比逐条查询更高效。

2.树型表查询

树型表举例:

方法一:递归(适用于多级的情况)
private List<CategoryInfo> convertLine2Tree(List<CategoryInfo> dataList, Integer pid) {//pid:0List<CategoryInfo> children = new ArrayList();                          for (CategoryInfo m : dataList) {if (m.getCategoryId() != null && m.getpCategoryId() != null && m.getpCategoryId().equals(pid)) {m.setChildren(convertLine2Tree(dataList, m.getCategoryId()));children.add(m);}}return children;}
方法二:表的自连接

层级固定的话用表的自连接

selectone.id            one_id,one.name          one_name,one.parentid      one_parentid,one.orderby       one_orderby,one.label         one_label,two.id            two_id,two.name          two_name,two.parentid      two_parentid,two.orderby       two_orderby,two.label         two_labelfrom course_category oneinner join course_category two on one.id = two.parentidwhere one.parentid = 1and one.is_show = 1and two.is_show = 1order by one.orderby,two.orderby

举例:

查询课程计划(树型结构)(这个树型结构固定为两层)

<!-- 课程分类树型结构查询映射结果 --><resultMap id="treeNodeResultMap" type="com.xuecheng.content.model.dto.TeachplanDto"><!-- 一级数据映射 --><id column="one_id" property="id"/><result column="one_pname" property="pname"/><result column="one_parentid" property="parentid"/><result column="one_grade" property="grade"/><result column="one_mediaType" property="mediaType"/><result column="one_startTime" property="startTime"/><result column="one_endTime" property="endTime"/><result column="one_orderby" property="orderby"/><result column="one_courseId" property="courseId"/><result column="one_coursePubId" property="coursePubId"/><!-- 一级中包含多个二级数据 --><!-- 映射子节点teachPlanTreeNodes,一对多映射,用collection--><collection property="teachPlanTreeNodes" ofType="com.xuecheng.content.model.dto.TeachplanDto"><!-- 二级数据映射 --><id column="two_id" property="id"/><result column="two_pname" property="pname"/><result column="two_parentid" property="parentid"/><result column="two_grade" property="grade"/><result column="two_mediaType" property="mediaType"/><result column="two_startTime" property="startTime"/><result column="two_endTime" property="endTime"/><result column="two_orderby" property="orderby"/><result column="two_courseId" property="courseId"/><result column="two_coursePubId" property="coursePubId"/><!-- 每个小章节子节点还对应着一个媒资视频文件 --><!-- 一对一映射用association --><association property="teachplanMedia" javaType="com.xuecheng.content.model.po.TeachplanMedia"><result column="teachplanMeidaId" property="id"/><result column="mediaFilename" property="mediaFilename"/><result column="mediaId" property="mediaId"/><result column="two_id" property="teachplanId"/><result column="two_courseId" property="courseId"/><result column="two_coursePubId" property="coursePubId"/></association></collection></resultMap><!-- 表的自连接 查询课程计划(树型结构)(这个树型结构固定为两层) --><select id="selectTreeNodes" parameterType="long" resultMap="treeNodeResultMap">select one.id            one_id,one.pname         one_pname,one.parentid      one_parentid,one.grade         one_grade,one.media_type    one_mediaType,one.start_time    one_startTime,one.end_time      one_endTime,one.orderby       one_orderby,one.course_id     one_courseId,one.course_pub_id one_coursePubId,two.id            two_id,two.pname         two_pname,two.parentid      two_parentid,two.grade         two_grade,two.media_type    two_mediaType,two.start_time    two_startTime,two.end_time      two_endTime,two.orderby       two_orderby,two.course_id     two_courseId,two.course_pub_id two_coursePubId,m1.media_fileName mediaFilename,m1.id             teachplanMeidaId,m1.media_id       mediaIdfrom teachplan oneLEFT JOIN teachplan two on one.id = two.parentidLEFT JOIN teachplan_media m1 on m1.teachplan_id = two.idwhere one.parentid = 0and one.course_id = #{cousrseId}order by one.orderby,two.orderby</select>

方法三:MySQL递归(既可以向下递归也可以向上递归)(MySQL8 支持)
with recursive t1 as (
select * from  course_category p where  id= '1'
union allselect t.* from course_category t inner join t1 on t1.id = t.parentid
)
select *  from t1 order by t1.id, t1.orderby

3.表的连接该怎么选择

1.等值连接&内连接

等值连接一定程度上就是内连接。

等值连接是内连接的一种,通常是内连接最常见和最基础的形式。

等值连接可以视为内连接的一种特例,因为等值连接只是内连接的一种情况,其中连接条件使用了相等运算符 (=)。换句话说,所有的等值连接都是内连接,但并非所有的内连接都是等值连接。

内连接允许使用各种比较运算符(包括等于、不等于、大于、小于等),而等值连接专门使用等于运算符(=)作为连接条件。

SELECT a.id, b.name
FROM table_a a,table_b b 
WHERE a.id = b.id;
这是最开始学的等值连接写法。实际上和下面的内连接意义相同。
SELECT a.id, b.name
FROM table_a a
INNER JOIN table_b b ON a.id = b.id;SELECT orders.id, customers.name
FROM orders
INNER JOIN customers ON orders.customer_id = customers.id;
这是内连接的写法。
2.左连接&右连接&外连接

左连接

  • 定义:左连接返回左表中的所有记录,即使右表中没有匹配的记录。如果右表中没有匹配的记录,结果会显示为 NULL
  • 使用场景:当你希望获取左表中所有数据,包括没有匹配数据的记录时使用。
  • 示例:查询所有客户及他们的订单(即使客户没有订单也要显示)。
SELECT customers.name, orders.id
FROM customers
LEFT JOIN orders ON customers.id = orders.customer_id;

这个查询会返回所有客户及他们的订单,如果客户没有订单,则订单字段为 NULL

右连接(用的比较少)

  • 定义右连接与左连接类似,但它返回的是右表中的所有记录。如果左表中没有匹配的记录,结果会显示为 NULL
  • 使用场景:这种连接方式使用得较少,通常在需要保留右表的所有数据时才使用。
  • 示例:查询所有订单和对应的客户信息(即使某个订单没有关联客户)。
SELECT orders.id, customers.name
FROM orders
RIGHT JOIN customers ON orders.customer_id = customers.id;

外连接(用的很少)

  • 定义:外连接返回左表和右表中的所有记录,当某一表没有匹配的记录时,另一个表中的字段会填充 NULL。不过需要注意,MySQL 不直接支持 FULL OUTER JOIN,可以通过使用 LEFT JOINRIGHT JOIN 结合来模拟。
  • 使用场景:当你希望返回两个表中所有的记录(无论是否匹配)时使用。
  • 示例:没有直接的支持,你可以通过组合 LEFT JOINRIGHT JOIN 来模拟:
SELECT * FROM A
LEFT JOIN B ON A.id = B.id
UNION
SELECT * FROM A
RIGHT JOIN B ON A.id = B.id;
3.自连接

一个表与它自己连接,通常用来查找同一表中的关联数据。

使用自连接一定要给表取别名。

至于自连接的实现方式的选择就要看具体情况了:

自连接通常使用 内连接左连接,具体选择取决于你是否需要保留左表的所有记录。

  • 如果你只关心表中有匹配关系的记录,使用 内连接
  • 如果你希望保留表中的所有记录(即使没有匹配的记录),使用 左连接

相关文章:

SQL写法技巧

目录 1.批量插入&#xff0c;查询&#xff0c;删除数据 缺点 实现方法 1.批量插入数据 2.批量查询数据 3.批量删除数据 4.批量修改数据 解释 2.树型表查询 方法一&#xff1a;递归(适用于多级的情况) 方法二&#xff1a;表的自连接 方法三&#xff1a;MySQL递归&am…...

Ryu:轻量开源,开启 SDN 新程

1. Ryu 控制器概述 定位&#xff1a;轻量级、开源的SDN控制器&#xff0c;专为开发者和研究人员设计&#xff0c;基于Python实现。开发者&#xff1a;由日本NTT实验室主导开发&#xff0c;遵循Apache 2.0开源协议。核心理念&#xff1a;简化SDN应用开发&#xff0c;提供友好的…...

【核心算法篇十四】《深度解密DeepSeek量子机器学习:VQE算法加速的黑科技与工程实践》

在经典计算机逼近物理极限的今天,量子计算正以指数级加速潜力颠覆传统计算范式。想象一下,一个需要超级计算机运算千年的化学分子模拟问题,用量子计算机可能只需几分钟——这就是DeepSeek团队在VQE(Variational Quantum Eigensolver)算法加速实践中创造的奇迹。根据,VQE作…...

“国补”带火手机换新,出售旧手机应如何保护个人信息安全

在“国补”政策的推动下,手机换新热潮正席卷而来。“国补”以其诱人的补贴力度,成功激发了消费者更换手机的热情。无论是渴望体验最新技术的科技爱好者,还是对旧手机性能不满的普通用户,都纷纷投身到这场手机换新的浪潮之中。 随着大量消费者参与手机换新,二手手机市场迎来…...

数据结构:基数排序(c++实现)

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》《Linux》《网络》 《redis学习笔记》 文章目录 基数排序的定义和基本原理基本原理具体步骤 基数排序的优缺点&#xff1a;代码实现总结 基数排序的定义和基本原理 基数排序(Radix Sort)是一…...

eNSP下载安装(eNsp、WinPcap、Wireshark、VirtualBox下载安装)

一、下载 下载网址&#xff1a;https://cloud.grbj.cn/softlink/eNSP%20V100R003C00SPC100%20Setup.exe 备用临时网址&#xff1a;https://linshi.grbj.cn/abdpana/softlink 二、准备工作 系统要求 关闭防火墙 三、安装 3.1安装WinPcap 基本都是下一步&#xff0c;双击&…...

【Linux系统】—— 冯诺依曼体系结构与操作系统初理解

【Linux系统】—— 冯诺依曼体系结构与操作系统初理解 1 冯诺依曼体系结构1.1 基本概念理解1.2 CPU只和内存打交道1.3 为什么冯诺依曼是这种结构1.4 理解数据流动 2 操作系统2.1 什么是操作系统2.2 设计OS的目的2.3 操作系统小知识点2.4 如何理解"管理"2.5 系统调用和…...

Linux 权限系统和软件安装(二):深入理解 Linux 权限系统

在 Linux 的世界里&#xff0c;权限系统犹如一位忠诚的卫士&#xff0c;严密守护着系统中的文件与目录&#xff0c;确保只有具备相应权限的用户才能进行操作。与其他一些操作系统不同&#xff0c;Linux 并不依据文件后缀名来标识文件的操作权限&#xff0c;而是构建了一套独特且…...

Windows 中的启动项如何打开?管理电脑启动程序的三种方法

在日常使用电脑时&#xff0c;我们经常会发现一些应用程序在开机时自动启动&#xff0c;这不仅会拖慢系统的启动速度&#xff0c;还可能占用不必要的系统资源。幸运的是&#xff0c;通过几个简单的步骤&#xff0c;你可以轻松管理这些开机自启的应用程序。接下来&#xff0c;我…...

uniapp邪门事件

很久之前在这篇《THREEJS 在 uni-app 中使用&#xff08;微信小程序&#xff09;》&#xff1a;THREEJS 在 uni-app 中使用&#xff08;微信小程序&#xff09;_uni-app_帶刺的小葡萄-华为开发者空间 中学到了如何在uniapp的微信小程序里接入three.js的3d模型 由于小程序自身很…...

DeepSeek学习教程 从入门到精通pdf下载:快速上手 DeepSeek

下载链接&#xff1a;DeepSeek从入门到精通(清华大学).pdf 链接: https://pan.baidu.com/s/1Ym0-_x9CrFHFld9UiOdA5A 提取码: 2ebc 一、DeepSeek 简介 DeepSeek 是一款由中国团队开发的高性能大语言模型&#xff0c;具备强大的推理能力和对中文的深刻理解。它广泛应用于智能办…...

MATLAB进阶之路:数据导入与处理

在MATLAB的学习旅程中,我们已经初步了解了它的基础操作。如今,我们将沿着这条充满惊喜的道路,迈向下一个重要的站点——数据导入与处理。这部分内容就像是为MATLAB注入了强大的能量,使其能够从现实的数据世界中汲取信息,然后像一位智慧的魔法师一样,巧妙地处理这些数据,…...

百度首页上线 DeepSeek 入口,免费使用

大家好&#xff0c;我是小悟。 百度首页正式上线了 DeepSeek 入口&#xff0c;这一重磅消息瞬间在技术圈掀起了惊涛骇浪&#xff0c;各大平台都被刷爆了屏。 百度这次可太给力了&#xff0c;PC 端开放仅 1 小时&#xff0c;就有超千万人涌入体验。这速度&#xff0c;简直比火…...

安全见闻

今天学了Windows操作系统和驱动程序的相关知识 Windows注册表 注册表是windows系统中具有层次结构的核心数据库 储存的数据对windows 和Windows上运行的应用程序和服务至关重要。注册表时帮助windows控制硬件、软件、用户环境和windows界面的一套数据文件。 打开注册表编辑器…...

PLC通讯

PPI通讯 是西门子公司专为s7-200系列plc开发的通讯协议。内置于s7-200 CPU中。PPI协议物理上基于RS-485口&#xff0c;通过屏蔽双绞线就可以实现PPI通讯。PPI协议是一种主-从协议。主站设备发送要求到从站设备&#xff0c;从站设备响应&#xff0c;从站不能主动发出信息。主站…...

Image Downloader下载文章图片的WordPress插件

源码介绍 一个用于下载图片的WordPress插件&#xff0c;包含下载统计功能&#xff0c;支持任何主题使用 用户点击下载后自动打包该文章所有原始图片&#xff0c;并把文章标题作为压缩包的文件名。 不占用服务器空间&#xff0c;也不占网盘空间&#xff0c;直接利用浏览器的性…...

乐享数科:供应链金融—三个不同阶段的融资模式

供应链金融是与产业链紧密结合的融资模式&#xff0c;它主要体现在订单采购、存货保管、销售回款这三个不同的业务阶段&#xff0c;并针对这些阶段提供了相应的金融服务。以下是这三个阶段中主要的融资模式及其特点&#xff1a; 供应链金融融资模式主要分为以下几种&#xff1…...

Jenkins 创建 Node 到 Windows

Jenkins 创建 Node 到 Windows 一. 新建 Node Dashboard -> Manage Jenkins -> Manage Nodes and Clouds Dashboard -> Nodes -> New Node 二. 配置节点 Node&#xff1a;节点名 Description&#xff1a;节点描述 Number of executors&#xff1a;节点最大同…...

halcon机器视觉深度学习对象检测,物体检测

目录 效果图操作步骤软件版本halcon参考代码本地函数 get_distinct_colors()本地函数 make_neighboring_colors_distinguishable() 效果图 操作步骤 首先要在Deep Learning Tool工具里面把图片打上标注文本&#xff0c; 然后训练模型&#xff0c;导出模型文件 这个是模型 mod…...

【分布式数据一致性算法】Gossip协议详解

在分布式系统中&#xff0c;多个节点同时提供服务时&#xff0c;数据一致性是核心挑战。在多个节点中&#xff0c;若其中一个节点的数据发生了修改&#xff0c;其他节点的数据都要进行同步。 一种比较简单粗暴的方法就是 集中式发散消息&#xff0c;简单来说就是一个主节点同时…...

蓝桥杯笔记——递归递推

递归 0. 函数的概念 我们从基础讲起&#xff0c;先了解函数的概念&#xff0c;然后逐步引入递归&#xff0c;帮助同学们更好地理解递归的思想和实现方式。 函数是程序设计中的一个基本概念&#xff0c;简单来说&#xff0c;它是一段封装好的代码&#xff0c;可以在程序中多次…...

Vue 3 + Vite 项目中配置代理解决开发环境中跨域请求问题

在 Vue 3 Vite 项目中&#xff0c;配置代理是解决开发环境中跨域请求问题的常见方法。通过在 Vite 的配置文件中设置代理&#xff0c;可以将前端请求转发到后端服务器&#xff0c;从而避免浏览器的同源策略限制。 1. 创建 Vue 3 Vite 项目 首先&#xff0c;确保你已经安装了…...

【复现DeepSeek-R1之Open R1实战】系列7:GRPO原理介绍、训练流程和源码深度解析

【复现DeepSeek-R1之Open R1实战】系列博文链接&#xff1a; 【复现DeepSeek-R1之Open R1实战】系列1&#xff1a;跑通SFT&#xff08;一步步操作&#xff0c;手把手教学&#xff09; 【复现DeepSeek-R1之Open R1实战】系列2&#xff1a;没有卡也能训模型&#xff01;Colab跑Op…...

【Qt】可爱的窗口关闭确认弹窗实现

文章目录 ​​​实现思路界面构建交互逻辑实现颜色渐变处理圆形部件绘制 代码在主窗口的构造函数中创建弹窗实例ExitConfirmDialog 类代码ColorCircleWidget 类代码 今天在Qt实现了这样一个可互动的窗口&#xff08;上图由于录屏工具限制没有录制到鼠标&#xff09; ​​​实现…...

服务器通过 ollama 运行deepseek r1

1、服务器环境简介 56核 CPU64G 内存无显卡已安装 Ollama 2、下载模型与配置 正常可以通过 ollama pull 或 ollama run 命令直接下载&#xff0c;但通常会遇到连接超时、找不到网址等总理。因此&#xff0c;可以使用国内的模型站进行下载&#xff0c;在这里使用魔塔查找模型…...

计算机毕业设计SpringBoot+Vue.jst网上购物商城系统(源码+LW文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…...

自制操作系统前置知识汇编学习

今天要做什么&#xff1f; 为了更好的理解书中内容&#xff0c;需要学习下进制分析和汇编。 汇编语言其实应该叫叫机器指令符号化语言&#xff0c;目前的汇编语言是学习操作系统的基础。 一&#xff1a;触发器 电路触发器的锁存命令默认是断开的&#xff0c;是控制电路触发器…...

Unity制作游戏——前期准备:Unity2023和VS2022下载和安装配置——附安装包

1.Unity2023的下载和安装配置 &#xff08;1&#xff09;Unity官网下载地址&#xff08;国际如果进不去&#xff0c;进国内的官网&#xff0c;下面以国内官网流程为例子&#xff09; unity中国官网&#xff1a;Unity中国官网 - 实时内容开发平台 | 3D、2D、VR & AR可视化 …...

深度学习(5)-卷积神经网络

我们将深入理解卷积神经网络的原理&#xff0c;以及它为什么在计算机视觉任务上如此成功。我们先来看一个简单的卷积神经网络示例&#xff0c;它用干对 MNIST数字进行分类。这个任务在第2章用密集连接网络做过&#xff0c;当时的测试精度约为 97.8%。虽然这个卷积神经网络很简单…...

LeetCodehot 力扣热题100 课程表

题目背景 这个问题要求我们判断是否可以完成所有课程的学习。每门课程可能依赖其他课程作为前置课程&#xff0c;构成了一个有向图。我们需要确定是否存在环&#xff0c;若存在环&#xff0c;说明课程之间互相依赖&#xff0c;无法完成所有课程&#xff1b;如果不存在环&#x…...