<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                在一對多,多對一的關系中"關系"是由多方來維護的,比如教師與班級是一對多的關系,在班級表中使用teacher_id來記錄該班級與教師的對應的關系。 ![](https://img.kancloud.cn/6d/81/6d81d77e92740da0afcbaba447fcdaf3_407x125.png) 通過此字段的值不但能夠查詢出每個班級對應的教師是誰,還能夠根據教師ID反向查詢出該教師負責哪些班級。 但在多對多的關系中,我們并沒有在ER圖看到相似的字段。 ![](https://img.kancloud.cn/4d/0b/4d0b167fadb4466a8b473337f09d24a5_182x294.png) 我們即沒有在課程實體中發現有班級實體相關的字段,又沒有在班級實體中發現有課程相關的字段。其實在多對多的關系中,ER圖自動省略了兩個實體間的關聯表。也就是說班級與課程的多對多關系,真實的反應到數據表中對應ER圖如下: ![](https://img.kancloud.cn/f0/21/f0217ec0c458641bdc2055b85447b95e_382x323.png) 而為了更有效的表示兩個實體間多對多的關系,會忽略掉用為于存儲數據的中間表。在spring中也能夠自動生成中間表,在進行數據處理時就好像中間表不存在一樣。雖然中間表沒有得到有效的表示,但在在程序開發過程中遇到多對多的實際情況,我們要時刻的提醒自己中間表的存在,因為很多多對多關系中"莫名"的問題都是由于處理該中間表的方式不同而引發的。 # @ManyToMany 使用@ManyToMany注解來表示實體間的多對多關系: entity/Course.java ```java public class Course { ... @ManyToMany ? private List<Klass>? klasses = new ArrayList<>()?; // 省略getter/setter,請自行添加 ``` * ? 使用@ManyToMany注解來表示實體間多對多的關系 * ? 多個班級使用List表示 * ? 一般會對其進行初始化(這樣做有一定的好處) 運行應用,然后使用navicat打開數據庫查看生成的中間表的情況: ![](https://img.kancloud.cn/5d/d5/5dd554dc310f3ec5e2b0c02f322e329d_280x72.png) 近一步查看其數據表結構: ![](https://img.kancloud.cn/18/53/18536a8b82c40ff8c2fe51c13856b3a0_568x105.png) 查看索引: ![](https://img.kancloud.cn/de/dc/dedc0d6b6e8532b10eb2eeaf1c322e31_517x102.png) 查看外鍵: ![](https://img.kancloud.cn/59/39/5939d515eddae572833721cf02c29341_703x106.png) 總結: 1. 自動創建了`表名`+`屬性名`的數據表 2. 在數據表中有兩個字段,分別為`表名_id`以及`屬性名_id`,這兩個字段組成了聯合主鍵 3. 同時為兩個字段添加了對應的外鍵及索引 ## 測試 打開測試文件CourseTest,進行多對多測試如下: entity/CourseTest.java ```java ... @Autowired KlassRepository klassRepository; ... @Before public void before() { this.course = new Course(); this.course.setName(RandomString.make(4)); for (int i = 0; i < 2; i++) { Klass klass = new Klass(); klass.setName(RandomString.make(4)); klassRepository.save(klass); this.course.getKlasses().add(klass); ? } } ``` * ? 將班級添加到課程中 當前項目對數據庫的操作策略為:create-drop,即應用啟動時生成數據表,應該停止時刪除數據表。這樣一來,每次單元測試執行完畢后我們都會得到一個空庫。雖然這有利于單元測試的成功執行,但卻不利于單元測試生成的數據信息,當需要查看單元測試生成的數據信息時,將操作策略暫時修改為:create ![](https://img.kancloud.cn/3f/d5/3fd5162d8cb70d3cdb01ac60a87d2ecc_469x232.png) ``` spring.jpa.hibernate.ddl-auto=create ``` 然后停止剛剛運行的應用,并運行CourseTest中的save方法以測試保存操作。操作完成后查看數據表信息: 新建了兩個id分別為1,2的班級: ![](https://img.kancloud.cn/41/46/41462d679f07d91a9c47db8b127aa5d5_240x65.png) 新建了1個id為1的課程: ![](https://img.kancloud.cn/78/82/7882b97cc5653085c8b09cb95c964942_237x45.png) 在中間表中生成了兩條關聯數據: ![](https://img.kancloud.cn/bb/fa/bbfad907514942368ada63da14c4a01d_219x69.png) 關聯數據表示出:id為1的課程對應id為1,2的兩個班級。 # 查數據 spring自動添加完多對多的關系后,在進行數據查詢時還可以在我們需要的時候自動的查詢此多對多數據。CourseTest的save方法中新增代碼如下: entity/CourseTest.java ```java import org.springframework.transaction.annotation.Transactional; @Test @Transactional ? public void save() { this.courseRepository.save(this.course); Course course = this.courseRepository.findById(this.course.getId()).get(); course.getKlasses(); } ``` * ? 為了提升查詢的效率,在查詢中spring默認不進行多對多數據的讀取。若想讀取多對多的數據,需要加此注解`@Transactional` >[info] Transactional是設置數據庫事務的注解,spring為會每一次的請求自動添加一個事務,而spring的單元測試并不會自動添加此事務。所以在單元測試若要模擬真實的數據庫的事務情況,則應該在方法(或類)上添加@Transactional注解。本教程不計劃對相關知識進行講解,在此添加事務僅為了單元測試的演示。 然后在`course.getKlasses();`新增斷點,接著使用debug模式來啟用測試: ![](https://img.kancloud.cn/54/14/5414e22666a8f967ebd6b8a283ce1ff0_872x167.png) 查看變量信息如下: ![](https://img.kancloud.cn/72/ee/72eea2d4208d2da5bfba8314ab184e4c_528x239.png) # 更新數據 entity/CourseTest.java ```java @Test public void manyToManyUpdate() { // 保存原課程 this.courseRepository.save(this.course); // 新建班級 Klass klass = new Klass(); klass.setName(RandomString.make(6)); klassRepository.save(klass); // 刪除已存在的一個班級,新增新班級后更新 this.course.getKlasses().remove(0); this.course.getKlasses().add(klass); this.courseRepository.save(course); } ``` 請自行加入斷點進行測試,在過程中注意查看數據表的變化情況。 # 參考文檔 | 名稱 | 鏈接 | 預計學習時長(分) | | --- | --- | --- | | 源碼地址 | [https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step6.1.7](https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step6.1.7) | - |
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看