SpringDataJpa的使用之一對一、一對多、多對多?關(guān)系映射問題
SpringDataJpa的使用 -- 一對一、一對多、多對多 關(guān)系映射
本文主要講述 @OneToOne、@OneToMany、@ManyToOne、@ManyToMany
這四個關(guān)系映射注解的使用,以及其對應(yīng)的級聯(lián)關(guān)系
有四張表,分別是:學(xué)生表、家長表、教室表、教師表,它們的關(guān)聯(lián)關(guān)系如下:
- 學(xué)生 對 家長:一對一
- 學(xué)生 對 教室:多對一
- 學(xué)生 對 教師:多對多
項(xiàng)目依賴
必要的依賴有:mysql驅(qū)動、SpringBootWeb、SpringBootStarter、SpringDataJpa、SpringBootText、druid,其它的依賴可以按需添加。 如:lombok、
pom.xml 必要依賴
<!-- Spring Boot 都使用 2.4.5,看個人習(xí)慣 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.4.5</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.4.5</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-test</artifactId> <version>2.4.5</version> <scope>runtime</scope> </dependency> <!-- Spring Data JPA 使用 2.6.1,看個人習(xí)慣 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> <version>2.6.1</version> </dependency> <!-- mysql 驅(qū)動 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.25</version> <scope>runtime</scope> </dependency> <!-- druid 數(shù)據(jù)庫連接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.24</version> </dependency>
pom.xml 可選依賴
<!-- Spring 熱部署 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <version>2.4.5</version> <scope>runtime</scope> <optional>true</optional> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> <optional>true</optional> </dependency>
項(xiàng)目配置
application.yaml
spring: # DataSource datasource: driver-class-name: com.mysql.cj.jdbc.Driver username: 賬號 password: 密碼 # serverTimezone可以設(shè)置為北京時間GMT%2B8、上海時間Asia/Shanghai或者香港時間Hongkong url: jdbc:mysql://localhost:3306/cloudtext?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8 # DataBase Connection -- JPA jpa: # 顯示 SQL 語句 show-sql: true # 不允許在視圖階段 執(zhí)行 sql open-in-view: false # 建議設(shè)置一個不常用的,避免沖突 server: # 項(xiàng)目端口號 port: 8092 # 項(xiàng)目路徑 servlet: context-path: /jpa
sql文件(MySQL版)
cloudText.sql 僅結(jié)構(gòu)
-- ---------------------------- -- Table structure for classroom -- ---------------------------- DROP TABLE IF EXISTS `classroom`; CREATE TABLE `classroom` ( `class_room_id` tinyint unsigned NOT NULL AUTO_INCREMENT COMMENT '班級主鍵', `class_room_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '班級名稱', `class_room_location` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '班級位置', `class_room_capacity` int unsigned DEFAULT NULL COMMENT '班級人數(shù)', `class_room_grade` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '班級年級', PRIMARY KEY (`class_room_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin; -- ---------------------------- -- Table structure for patriarch -- ---------------------------- DROP TABLE IF EXISTS `patriarch`; CREATE TABLE `patriarch` ( `patriarch_id` tinyint unsigned NOT NULL AUTO_INCREMENT COMMENT '家長主鍵', `patriarch_name` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '家長姓名', `patriarch_age` int unsigned DEFAULT NULL COMMENT '家長年齡', `patriarch_sex` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '家長性別', `patriarch_phone` varchar(11) COLLATE utf8_bin DEFAULT NULL COMMENT '家長電話', `patriarch_address` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '家長住址', PRIMARY KEY (`patriarch_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin; -- ---------------------------- -- Table structure for student -- ---------------------------- DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `student_id` tinyint unsigned NOT NULL AUTO_INCREMENT COMMENT '學(xué)生主鍵', `student_name` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '學(xué)生姓名', `student_age` int unsigned DEFAULT NULL COMMENT '學(xué)生年齡', `student_sex` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '學(xué)生性別', `patriarch_id` tinyint unsigned NOT NULL COMMENT '家長外鍵', `class_room_id` tinyint unsigned DEFAULT NULL COMMENT '班級外鍵', PRIMARY KEY (`student_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin; -- ---------------------------- -- Table structure for student_teacher -- ---------------------------- DROP TABLE IF EXISTS `student_teacher`; CREATE TABLE `student_teacher` ( `student_id` tinyint unsigned NOT NULL COMMENT '學(xué)生主鍵', `teacher_id` tinyint unsigned NOT NULL COMMENT '教師主鍵', PRIMARY KEY (`student_id`,`teacher_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin; -- ---------------------------- -- Table structure for teacher -- ---------------------------- DROP TABLE IF EXISTS `teacher`; CREATE TABLE `teacher` ( `teacher_id` tinyint unsigned NOT NULL AUTO_INCREMENT COMMENT '教師主鍵', `teacher_name` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '教師姓名', `teacher_age` int unsigned DEFAULT NULL COMMENT '教師年齡', `teacher_sex` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '教師性別', `teacher_course` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '教師教授科目', PRIMARY KEY (`teacher_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin;
級聯(lián)關(guān)系簡述
- ALL -- 級聯(lián)
所有
操作 - PERSIST -- 級聯(lián)
持久化
操作 - MERGE -- 級聯(lián)
合并
操作 - REMOVE -- 級聯(lián)
刪除
操作 - REFRESH -- 級聯(lián)
刷新
操作(調(diào)用refresh方法才會刷新) - DETACH -- 級聯(lián)
分離
操作(2.0版本才有)
參考:《Spring Boot 整合——JPA 數(shù)據(jù)模型關(guān)聯(lián)操作(一對一、一對多、多對多)》
@OneToOne 一對一 關(guān)系映射
一對一關(guān)系的雙方必須有且僅有一方放棄維護(hù),在 @OneToOne 中添加mappedBy屬性表示放棄維護(hù)。
學(xué)生類(Student.java):維護(hù)方 家長類(Patriarch.java):被維護(hù)方
Student.java (主鍵和非外鍵屬性)
package com.ljm.exmaple.entity; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; import javax.persistence.OneToOne; import javax.persistence.Table; /** * 學(xué)生 類 * * @author LJM */ @Entity @Table(name = "STUDENT") public class Student { /** * 學(xué)生 id */ @Id @Column(name = "student_id", nullable = false) @GeneratedValue(strategy = GenerationType.IDENTITY) private Long studentId; /** * 學(xué)生 姓名 */ @Column(name = "student_name", nullable = false) private String studentName; /** * 學(xué)生 年齡 */ @Column(name = "student_age", nullable = false) private Short studentAge; /** * 學(xué)生 性別 */ @Column(name = "student_sex", nullable = false) private String studentSex; /** 省略 Constructor、Getter、Setter、toString 方法 **/ }
Patriarch.java (主鍵和非外鍵屬性)
package com.ljm.exmaple.entity; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToOne; import javax.persistence.Table; /** * 家長 類 * * @author LJM */ @Entity @Table(name = "PATRIARCH") public class Patriarch { /** * 家長 id */ @Id @Column(name = "patriarch_id", nullable = false) @GeneratedValue(strategy = GenerationType.IDENTITY) private Long patriarchId; /** * 家長 姓名 */ @Column(name = "patriarch_name", nullable = false) private String patriarchName; /** * 家長 年齡 */ @Column(name = "patriarch_age") private Short patriarchAge; /** * 家長 性別 */ @Column(name = "patriarch_sex", nullable = false) private String patriarchSex; /** * 家長 電話 */ @Column(name = "patriarch_phone", nullable = false, length = 11) private String patriarchPhone; /** * 家長 住址 */ @Column(name = "patriarch_address", nullable = false) private String patriarchAddress; /** 省略 Constructor、Getter、Setter、toString 方法 **/ }
1.無中間表,維護(hù)方添加外鍵,被維護(hù)方添加對應(yīng)項(xiàng)
cascade = CascadeType.ALL
表示:級聯(lián)關(guān)系。
fetch = FetchType.EAGER
表示:預(yù)加載。
name = "patriarch_id"
指定外鍵。
nullable = false
表示:不能為空。
unique = true
表示:不能重復(fù)。
mappedBy = "patriarch"
:添加了這個屬性表示放棄維護(hù)。
維護(hù)方的屬性添加到 Student.java 中。
被維護(hù)方的屬性添加到 Patriarch.java 中。
/** * 一對一 * 家長 外鍵 * 維護(hù)方 * 使用 CascadeType.ALL 亦可,區(qū)別不大 */ @OneToOne(cascade = {CascadeType.MERGE, CascadeType.REMOVE}, fetch = FetchType.EAGER) @JoinColumn(name = "patriarch_id", nullable = false, unique = true) private Patriarch patriarch; /** * 一對一 * 被維護(hù)方(對應(yīng)項(xiàng)) * 使用 CascadeType.ALL 亦可,區(qū)別不大 */ @OneToOne(mappedBy = "patriarch", cascade = {CascadeType.REFRESH, CascadeType.MERGE, CascadeType.REMOVE}, fetch = FetchType.EAGER) private Student student; /** 注意,外鍵及對應(yīng)項(xiàng)的 Getter、Setter 不要忘了 */
2.無中間表,維護(hù)方添加外鍵,被維護(hù)方不添加對應(yīng)項(xiàng)
cascade = CascadeType.ALL 表示:級聯(lián)關(guān)系。
fetch = FetchType.EAGER 表示:預(yù)加載。
name = "patriarch_id" 指定外鍵。
nullable = false 表示:不能為空。
unique = true 表示:不能重復(fù)。
維護(hù)方的屬性添加到 Student.java 中。
/** * 一對一 * 家長 外鍵 * 維護(hù)方 * 使用 CascadeType.ALL 亦可,區(qū)別不大 */ @OneToOne(cascade = {CascadeType.MERGE, CascadeType.REMOVE}, fetch = FetchType.EAGER) @JoinColumn(name = "patriarch_id", nullable = false, unique = true) private Patriarch patriarch; /** * 一對一 * 被維護(hù)方(對應(yīng)項(xiàng)),不需要添加對應(yīng)項(xiàng) * 使用 CascadeType.ALL 亦可,區(qū)別不大 */ /** * @OneToOne(mappedBy = "patriarch", cascade = {CascadeType.REFRESH, CascadeType.MERGE, CascadeType.REMOVE}, fetch = FetchType.EAGER) * private Student student; */ /** 注意,外鍵的 Getter、Setter 不要忘了 */
3.有中間表,維護(hù)方不添加外鍵,被維護(hù)方不添加對應(yīng)項(xiàng)
暫缺,這不是本文重點(diǎn),以后可能會添加。
不需要使用關(guān)系注解 @OneToOne、@OneToMany、@ManyToOne、@ManyToMany,沒有外鍵。
@OneToMany、@ManyToOne 一對多 關(guān)系映射
一對多關(guān)系中,多方必須維護(hù)外鍵,一方一般不維護(hù)(我在某篇文章中看到:說一方也可以維護(hù)外鍵,我還未驗(yàn)證)。
學(xué)生類(Student.java):維護(hù)方
教室類(ClassRoom.java):被維護(hù)方
Student.java (主鍵和非外鍵屬性)
package com.ljm.exmaple.entity; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; import javax.persistence.OneToOne; import javax.persistence.Table; /** * 學(xué)生 類 * * @author LJM */ @Entity @Table(name = "STUDENT") public class Student { /** * 學(xué)生 id */ @Id @Column(name = "student_id", nullable = false) @GeneratedValue(strategy = GenerationType.IDENTITY) private Long studentId; /** * 學(xué)生 姓名 */ @Column(name = "student_name", nullable = false) private String studentName; /** * 學(xué)生 年齡 */ @Column(name = "student_age", nullable = false) private Short studentAge; /** * 學(xué)生 性別 */ @Column(name = "student_sex", nullable = false) private String studentSex; /** 省略 Constructor、Getter、Setter、toString 方法 **/ }
ClassRoom.java (主鍵和非外鍵屬性)
package com.ljm.exmaple.entity; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; /** * 教室 類 * * @author LJM */ @Entity @Table(name = "CLASSROOM") public class ClassRoom { /** * 教室 id */ @Id @Column(name = "classRoom_id", nullable = false) @GeneratedValue(strategy = GenerationType.IDENTITY) private Long classRoomId; /** * 教室 名稱 */ @Column(name = "classRoom_name", nullable = false) private String classRoomName; /** * 教室 位置 */ @Column(name = "classRoom_location", nullable = false) private String classRoomLocation; /** * 教室 容量 */ @Column(name = "classRoom_capacity", nullable = false) private Short classRoomCapacity; /** * 教室 所在的 班級的年級(小學(xué)到高中) */ @Column(name = "classRoom_grade", nullable = false) private String classRoomGrade; /** 省略 Constructor、Getter、Setter、toString 方法 **/ }
1.無中間表,多方維護(hù)并添加外鍵,一方被維護(hù)
cascade = CascadeType.XXX 表示:級聯(lián)關(guān)系。
fetch = FetchType.EAGER 表示:預(yù)加載。
name = "classRoom_id" 指定外鍵。
nullable = false 表示:不能為空。
mappedBy = "classRoom" :添加了這個屬性表示放棄維護(hù),在一對多的一方用來指向多方的那個外鍵屬性。
/** * 多對一 * 多方 * 教室外鍵 * 維護(hù)方,級聯(lián)關(guān)系為 none(沒有,默認(rèn)) */ @JoinColumn(name = "classRoom_id", nullable = false) @ManyToOne(fetch = FetchType.EAGER) private ClassRoom classRoom; /** * 一對多 * 一方 * (被)維護(hù)方(對應(yīng)項(xiàng)) * 被維護(hù)方代碼 */ @OneToMany(mappedBy = "classRoom", cascade = {CascadeType.MERGE, CascadeType.REFRESH}, fetch = FetchType.EAGER) private List<Student> studentList; /** 注意,外鍵及對應(yīng)項(xiàng)的 Getter、Setter 不要忘了 */
2.有中間表,多方維護(hù),一方被維護(hù)
暫缺,這不是本文重點(diǎn),以后可能會添加。
不需要使用關(guān)系注解 @OneToOne、@OneToMany、@ManyToOne、@ManyToMany,沒有外鍵。
3.無中間表,多方維護(hù),一方也維護(hù)
暫缺,待驗(yàn)證。
@ManyToMany 多對多 關(guān)系映射
多對多關(guān)系中,必須有且僅有一方放棄維護(hù)外鍵,需要新建中間表,但不需要寫對應(yīng)的實(shí)體類。
學(xué)生類(Student.java):維護(hù)方
教師類(Teacher.java):被維護(hù)方
Student.java (主鍵和非外鍵屬性)
package com.ljm.exmaple.entity; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; import javax.persistence.OneToOne; import javax.persistence.Table; /** * 學(xué)生 類 * * @author LJM */ @Entity @Table(name = "STUDENT") public class Student { /** * 學(xué)生 id */ @Id @Column(name = "student_id", nullable = false) @GeneratedValue(strategy = GenerationType.IDENTITY) private Long studentId; /** * 學(xué)生 姓名 */ @Column(name = "student_name", nullable = false) private String studentName; /** * 學(xué)生 年齡 */ @Column(name = "student_age", nullable = false) private Short studentAge; /** * 學(xué)生 性別 */ @Column(name = "student_sex", nullable = false) private String studentSex; /** 省略 Constructor、Getter、Setter、toString 方法 **/ }
Teacher.java (主鍵和非外鍵屬性)
package com.ljm.exmaple.entity; import java.util.List; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.ManyToMany; import javax.persistence.Table; /** * 教師 類 * * @author LJM */ @Entity @Table(name = "TEACHER") public class Teacher { /** * 教師 id */ @Id @Column(name = "teacher_id", nullable = false) @GeneratedValue(strategy = GenerationType.IDENTITY) private Long teacherId; /** * 教師 姓名 */ @Column(name = "teacher_name", nullable = false) private String teacherName; /** * 教師 年齡 */ @Column(name = "teacher_age") private Integer teacherAge; /** * 教師 性別 */ @Column(name = "teacher_sex", nullable = false) private String teacherSex; /** * 教師 所教的 科目 */ @Column(name = "teacher_course", nullable = false) private String teacherCourse; /** 省略 Constructor、Getter、Setter、toString 方法 **/ }
fetch = FetchType.EAGER 表示:預(yù)加載。
name = "student_teacher" 指定關(guān)聯(lián)關(guān)系表。
joinColumns = @JoinColumn(name = "student_id") 指定我方在關(guān)聯(lián)表中對應(yīng)的主鍵。
inverseJoinColumns = @JoinColumn(name = "teacher_id") 指定被維護(hù)方在關(guān)聯(lián)表中對應(yīng)的主鍵。
mappedBy = "teacherList" :添加了這個屬性表示放棄維護(hù),維護(hù)方用來指向另一方的那個外鍵屬性。
/** * 多對多 * 維護(hù)方 * 教師 外鍵 * 級聯(lián)關(guān)系為 none(沒有,默認(rèn)),雙方互不干擾 */ @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "student_teacher", joinColumns = @JoinColumn(name = "student_id"), inverseJoinColumns = @JoinColumn(name = "teacher_id")) private List<Teacher> teacherList; /** * 多對多 * 被維護(hù)方 * 學(xué)生 外鍵(對應(yīng)項(xiàng)) * 級聯(lián)關(guān)系為 none(沒有,默認(rèn)),雙方互不干擾 */ @ManyToMany(mappedBy = "teacherList", fetch = FetchType.EAGER) private List<Student> studentList; /** 注意,外鍵及對應(yīng)項(xiàng)的 Getter、Setter 不要忘了 */
本文參考
Spring Data JPA之一對一,一對多,多對多關(guān)系映射
到此這篇關(guān)于SpringDataJpa的使用之一對一、一對多、多對多 關(guān)系映射的文章就介紹到這了,更多相關(guān)SpringDataJpa使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring 中 BeanFactoryPostProcessor 的作用和示例源碼分析
Spring的BeanFactoryPostProcessor是容器初始化的擴(kuò)展接口,允許在Bean實(shí)例化前修改或擴(kuò)展Bean的配置元數(shù)據(jù),本文給大家介紹Spring 中 BeanFactoryPostProcessor 的作用和示例源碼分析,感興趣的朋友一起看看吧2025-03-03解讀java?try?catch?異常后還會繼續(xù)執(zhí)行嗎
這篇文章主要介紹了解讀java?try?catch?異常后還會不會繼續(xù)執(zhí)行問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-11-11JAVA“無法驗(yàn)證證書。將不執(zhí)行該應(yīng)用程序?!碧崾窘鉀Q辦法
這篇文章主要給大家介紹了關(guān)于JAVA“無法驗(yàn)證證書,將不執(zhí)行該應(yīng)用程序”提示的解決辦法,要解決Java無法驗(yàn)證證書的問題,可以嘗試下本文的方法,需要的朋友可以參考下2024-03-03JAVA構(gòu)造函數(shù)不能使用void關(guān)鍵字問題
這篇文章主要介紹了JAVA構(gòu)造函數(shù)不能使用void關(guān)鍵字問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03SpringBoot獲取application.properties文件中文亂碼問題及解決
這篇文章主要介紹了SpringBoot獲取application.properties文件中文亂碼問題及解決,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05基于Spring Boot使用JpaRepository刪除數(shù)據(jù)時的注意事項(xiàng)
這篇文章主要介紹了Spring Boot使用JpaRepository刪除數(shù)據(jù)時的注意事項(xiàng),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06SpringBoot+ENC實(shí)現(xiàn)密鑰加密的使用示例
本文主要介紹了SpringBoot+ENC實(shí)現(xiàn)密鑰加密的使用示例,主要是為了將配置信息從應(yīng)用程序代碼中分離出來,以提高安全性和可維護(hù)性,感興趣的可以了解一下2024-07-07