標籤:pre 關係 upd any java 計算 name app 導致
本文來是從 java web輕量級開發面試教程從摘錄的。
Inverse的英文含義是反轉,在Hibernate中用來決定是由哪方來維護兩個業務實體類之間的關聯關係,具體而言,就是由哪方去設定這個被外鍵約束的欄位值。
它的預設值是false,也就是說,本端(比如inverse=false寫在學生端,那麼本端是學生,另外一方是課程)不“反轉控制權”,這句彆扭的話的另外一種說法是,本端維護關聯關係。如果兩邊都不寫,那麼兩端都維護。這樣會造成問題,即新時因為兩端都控制關係,因此可能會導致重複更新。
注意,inverse僅僅是指定由誰來設定外索引值,而不是用來設定級聯操作,級聯操作的方式由cascade來負責,很多人會混淆它們的含義和用法。
這個例子所用到的資料表是Person表和Card表,其中Person表裡包含ID、Name和Phone欄位,而Card表裡包含了CardID、PersonID、Bank和balance四個欄位。
在hibernate.cfg.xml檔案裡,通過mapping resource來指定對應的對應檔,其中關鍵的代碼如下:
1<!-- 添加實體類的對應檔-->2<mapping resource="Model/Card.hbm.xml" />3<mapping resource="Model/Person.hbm.xml" />
在Person.hbm.xml裡,用如下代碼來指定人(一方)和卡(多方)的關係,其中在人這一端,inverse是true。
1<set name="cards" cascade="save-update" inverse="true">2<key column="PersonID"/>3<one-to-many class="Card"/>4</set>
在HibernateMain.java裡,通過如下關鍵代碼插入了一個人的資訊。
1//建立一張卡2Card card1 = new Card();3 card1.setCardID("Card123");4 card1.setPersonID("Person123");5 card1.setBank("Citi");6 card1.setBalance(100f);7//初始化一個人8 Person person = new Person();9 person.setID("Person123");10 person.setName("Peter");11 person.setPhone("123456");12//在cards這個set裡加入card113 Set<Card> cards = new HashSet<Card>();14 cards.add(card1);15 person.setCards(cards);16//儲存人的資訊17 session.save(person);18 session.flush();
運行後,在輸出資訊裡能看到如下兩條相關的插入語句:一條是插入Person資訊,另一條是插入card資訊。
1 Hibernate: insert into Person (Name, Phone, ID) values (?, ?, ?)
2 Hibernate: insert into Card (PersonID, Bank, Balance, Person, CardID) values (?, ?, ?, ?, ?)
當把person.hbm.xml裡的inverse設定成false時,能看到相關的語句裡會多出一句update語句。
1 Hibernate: insert into Person (Name, Phone, ID) values (?, ?, ?)
2 Hibernate: insert into Card (PersonID, Bank, Balance, Person, CardID) values (?, ?, ?, ?, ?)
3 Hibernate: update Card set PersonID=? where CardID=?
原因是,當設定inverse為true時,Person這一端反轉外鍵控制權,也就是由Card這端來管理外鍵,而在代碼裡我們僅僅是插入了Person,沒有插入Card,所以就沒有更新兩個外鍵(PersonID和CardID)的操作。相反,當inverse為false時,管理外鍵控制權是在Person端,那麼當插入Person時,Hibernate就需要額外的一句update語句來管理外鍵了。
在一對多的例子裡,inverse不論取什麼值,對結果都沒有影響,所以很容易讓人忽視它的作用。
在一對多的例子裡,一般是讓多方來管理外鍵控制權,比如一個人有100張開,那麼如果由Person方來管理的話,無形中可能會多出100個update操作,效率上就不大好了。
如果在一對多案例中,inverse只是影響效率的話,那麼在多對多的例子中,inverse的設定就可能影響到資料。
我們再來看個多對多的學生選課案例,其中一個學生可以選多門課,而一門課裡可以有多個學生。在Student.hbm.xml裡,描述多對多關係的語句裡可加上inverse=“true”的語句。
1<set name="courses" table="students_courses" inverse= "true" cascade="save-update">2<key column="student_id"></key>3<many-to-many class="Model.Course" column="course_id"></many-to-many>4</set>
在Course.hbm.xml裡,不加任何關於inverse的語句,也就是說,在Student端反轉外鍵控制權,把控制權交到Course端。
在HibernateMain這個類裡,通過如下代碼讓s1學生選修電腦課程。
1 //設定一個學生,學號是12Student s1 = new Student();3 s1.setStudentID("1");4 s1.setStudentName("Peter");5//設定多個課程6 Course c1 = new Course();7 c1.setCourseID("c1");8 c1.setCourseName("Math");9 Course c2 = new Course();10 c2.setCourseID("c2");11 c2.setCourseName("Java");12 Course c3 = new Course();13 c3.setCourseID("c3");14 c3.setCourseName("C#");15//設定電腦課程這個Set16 Set<Course> computerCourses = new HashSet<Course>();17 computerCourses.add(c2);18 computerCourses.add(c3);19//讓s1這個學生選修電腦課程(也就是c2和c3課程)20 s1.setCourses(computerCourses);21//儲存s122 session.save(s1);23 session.flush();
執行結果是,雖然能在Student和Course表裡看到相關的學生和課程的記錄,但在關鍵的描述學生選課關聯表(students_courses)裡,看不到任何關聯記錄。原因是已經通過設定inverse把外鍵管理權交給Course方了,這裡僅僅是儲存學生,並沒有儲存課程,所以沒有插入外鍵的動作。如果要在students_courses表裡插入外部索引鍵關聯,就需要在person.hbm.xml裡設定inverse的值為false。
所以,在多對多關聯裡,設定錯了inverse值會導致結果出錯,請大家根據具體項目的情況適當設值。
Hibernate(或其它ORM)裡的inverse用法詳解,內容摘自Java web輕量級開發面試教程