hibernate 中 inverse的设置对效率的影响

阅读更多
java 代码

 

  1. 双向关联与inverse设定    
  2.  之前我们对User与Room作了单向的多对一以及反过来的一对多关联,我们也可以让User与Room彼此参考,形成双向关联,就User与Room对象,具体来说,就是将程序如下设计:    
  3. User.java    
  4. package onlyfun.caterpillar;    
  5.   
  6. public class User {    
  7. private long id;    
  8. private String name;    
  9. private Room room;    
  10.   
  11. public long getId() {    
  12. return id;    
  13. }    
  14. public void setId(long id) {    
  15. this.id = id;    
  16. }    
  17. public String getName() {    
  18. return name;    
  19. }    
  20. public void setName(String name) {    
  21. this.name = name;    
  22. }    
  23. public Room getRoom() {    
  24. return room;    
  25. }    
  26.   
  27. public void setRoom(Room room) {    
  28. this.room = room;    
  29. }    
  30. }    
  31. Room.java    
  32. package onlyfun.caterpillar;    
  33.   
  34. import java.util.*;    
  35.   
  36. public class Room {    
  37. private long id;    
  38. private String address;    
  39. private Set users = new HashSet();    
  40.   
  41. public long getId() {    
  42. return id;    
  43. }    
  44. public void setId(long id) {    
  45. this.id = id;    
  46. }    
  47. public String getAddress() {    
  48. return address;    
  49. }    
  50. public void setAddress(String address) {    
  51. this.address = address;    
  52. }    
  53. public Set getUsers() {    
  54. return users;    
  55. }    
  56. public void setUsers(Set users) {    
  57. this.users = users;    
  58. }    
  59. }    
  60.  而其对应的映射文件如下,首先是User.hbm.xml:    
  61. User.hbm.xml    
  62. "1.0"?>    
  63. PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"    
  64. "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">    
  65.   
  66.     
  67.   
  68. <class name="onlyfun.caterpillar.User" table="USER">    
  69.   
  70. "id" column="USER_ID" unsaved-value="0">    
  71. class="increment"/>    
  72.     
  73.   
  74. "name">    
  75. "NAME" length="16" not-null="true"/>    
  76.     
  77.   
  78. "room"    
  79. column="ROOM_ID"    
  80. class="onlyfun.caterpillar.Room"/>    
  81. class>    
  82.   
  83.     
  84.  再来是Room.hbm.xml:    
  85. Room.hbm.xml    
  86. "1.0"?>    
  87. PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"    
  88. "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">    
  89.   
  90.     
  91.   
  92. <class name="onlyfun.caterpillar.Room" table="ROOM">    
  93.   
  94. "id" column="ROOM_ID" unsaved-value="0">    
  95. class="increment"/>    
  96.     
  97.   
  98. "address" type="string"/>    
  99.   
  100. "users" table="USER" cascade="all">    
  101. "ROOM_ID"/>    
  102. class="onlyfun.caterpillar.User"/>    
  103.     
  104. class>    
  105.   
  106.     
  107.  这就形成了User与Room之间的双向关联映射,我们可以使用以下的程序进行测试:    
  108. HibernateTest.java    
  109. import onlyfun.caterpillar.*;    
  110. import net.sf.hibernate.*;    
  111. import net.sf.hibernate.cfg.*;    
  112.   
  113. public class HibernateTest {    
  114. public static void main(String[] args) throws HibernateException {    
  115. SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();    
  116.   
  117. Room room = new Room();    
  118. room.setAddress("NTU-M8-419");    
  119.   
  120. User user1 = new User();    
  121. user1.setName("bush");    
  122.   
  123. User user2 = new User();    
  124. user2.setName("bush");    
  125.   
  126. /*   
  127. * 因为没有设定inverser,所以只须从parent维护即可   
  128. */    
  129. //user1.setRoom(room);    
  130. //user2.setRoom(room);    
  131.   
  132. room.getUsers().add(user1);    
  133. room.getUsers().add(user2);    
  134.   
  135. Session session = sessionFactory.openSession();    
  136. Transaction tx= session.beginTransaction();    
  137. session.save(room);    
  138.   
  139. tx.commit();    
  140. session.close();    
  141.   
  142. sessionFactory.close();    
  143. }    
  144. }    
  145.  基本上就数据的储存来说,这样就已经足够,但这样的设计会有效能问题,显然的,这个程序将Room与User之间的关联交由Room来维持,就Room而言,它要先储存自已,然后储存其所包括的多个User,之后再对每一个User更新(update)对自己(Room)的关联,具体而言,这个程序必须实行以下的SQL:    
  146. Hibernate: insert into ROOM (address, ROOM_ID) values (?, ?)    
  147. Hibernate: insert into USER (NAME, ROOM_ID, USER_ID) values (?, ?, ?)    
  148. Hibernate: insert into USER (NAME, ROOM_ID, USER_ID) values (?, ?, ?)    
  149. Hibernate: update USER set ROOM_ID=? where USER_ID=?    
  150. Hibernate: update USER set ROOM_ID=? where USER_ID=?    
  151.  就Room而言,它并不知道其所包括的User是不是一个已储存的对象,或者即使为已储存对象,也不知道USER表格上的ROOM_ID是不是参考至ROOM表格的ROOM_ID上,所以它必须针对自己所包括的User对象一个个进行更新,以确保USER表格上的ROOM_ID是指向自己。    
  152.  如果将关联的维护交给User的话会比较容易,因为每个User都对应至一个Room,在储存时并用像Room一样必须对Set中的每个对象作检查,为了将关联的维护交给User,我们可以在Room.hbm.xml中的修改,加上inverse="true",表示将关联的维护「反过来」交给User作:    
  153. Room.java    
  154. "users" table="USER" inverse="true" cascade="all">    
  155. "ROOM_ID"/>    
  156. class="onlyfun.caterpillar.User"/>    
  157.     
  158.  由于将关联的维护交给User来作了,所以我们必须在储存时,明确的将Room设定给User,也就是说,必须这样作:    
  159. /*   
  160. * 因为有user维护关联,所以必须呼叫setRoom   
  161. */    
  162. user1.setRoom(room);    
  163. user2.setRoom(room);    
  164.   
  165. room.getUsers().add(user1);    
  166. room.getUsers().add(user2);    
  167.  这比不加上inverse="true"设定时多了个指定的动作,您必须多键几个字,所带来的是效率上的增加,Hibernate的持久层管理员会先储存Room,然后储存User,如此就可以省去之前再进行更新的动作,具体来说,就是会执行以下的SQL:    
  168. Hibernate: insert into ROOM (address, ROOM_ID) values (?, ?)    
  169. Hibernate: insert into USER (NAME, ROOM_ID, USER_ID) values (?, ?, ?)    
  170. Hibernate: insert into USER (NAME, ROOM_ID, USER_ID) values (?, ?, ?)    
  171.  与先前不同的是,由于关联交给了User维护,所以这次Room不用一一更新USER以确定每个ROOM_ID都指向自已。    
  172.  如果指定了inverse="true",而不确实的将Room指定给User会如何?那么User与Room会各自储存,但彼此没有关联,也就是User将不会参考至Room,USER表格的ROOM_ID将为null,例如:    
  173. mysql> select * from USER;    
  174. +---------+------+---------+    
  175. | USER_ID | NAME | ROOM_ID |    
  176. +---------+------+---------+    
  177. 1 | bush | NULL |    
  178. +---------+------+---------+    
  179.   
  180. mysql> select * from ROOM;    
  181. +---------+------------+    
  182. | ROOM_ID | address |    
  183. +---------+------------+    
  184. 1 | NTU-M8-419 |    
  185. +---------+------------+    
  186.  作个总结,在设立双向关联时,关联由多对一中「多」的哪一方维护,会比由「一」的哪一方维护来的方便,在Hibernate可以藉由inverse来设定,不设定inverse基本上也可以运行,但是效能会较差。    
  187.  设定了inverse,必须要明确的设定双方的参考,以这个主题的例子,Room要设定给User,而User也要知道Room的存在,这比不设定inverse需要键入较多的字,但从另一方面,比较符 合程序设计的直觉(单看User与Room类别,两者要互相参考时,本来就要明确设定)。    

你可能感兴趣的:(Hibernate,MySQL,XML,.net,SQL)