hibernate 多对多关系总结

    hibernate中,对对象关系的映射处理估计是最让人迷惑和头疼的,特别是cascade和inverse属性的使用,不知已经杀死了我多少个脑细胞了,好记性永远比不上烂笔头,为了能节省自己的脑细胞,降低猝死的出现概率,暂且在此记录一下自己的学习内容,以便日后查阅:

实体对象关系说明:

    1、用户类(user)->tb_pms_user

    2、用户组(group)->tb_pms_group

   其中,一个用户组可以包含多个用户,一个用户可以加入多个用户组,多对多关系。

Spring的配置文件:

  1 <?xml version="1.0" encoding="UTF-8"?>  
  2     <beans xmlns="http://www.springframework.org/schema/beans"  
  3            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4            xmlns:aop="http://www.springframework.org/schema/aop"  
  5           xmlns:tx="http://www.springframework.org/schema/tx"  
  6            xmlns:jee="http://www.springframework.org/schema/jee"  
  7            xsi:schemaLocation="  
  8            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd  
  9           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd  
 10           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd  
 11           http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">  
 12           
 13           <bean id="propertyConfigurer"  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
 14            <property name="locations">  
 15             <list>    
 16                <value>/WEB-INF/deploy/pms/app-config/jdbc.properties</value>   
 17              </list> 
 18               </property> 
 19             </bean>
 20           
 21           
 22           <!-- 配置数据原 -->
 23             <bean id="dataSource"
 24                class="org.apache.commons.dbcp.BasicDataSource">
 25             <property name="driverClassName"
 26                 value="com.mysql.jdbc.Driver">
 27             </property>
 28             <property name="url" value="jdbc:mysql://localhost:3306/pms"></property>
 29             <property name="username" value="root"></property>
 30             <property name="password" value="1qaz!QAZ"></property>
 31            </bean>
 32        
 33        <!-- 配置session工厂 -->
 34        <bean id="sessionFactory"
 35           class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
 36             <property name="dataSource">
 37             <ref bean="dataSource" />
 38              </property>
 39            <property name="mappingResources">
 40             <list>
 41               <value>com/pms/entity/TbPmsGroup.hbm.xml</value> 
 42               <value>com/pms/entity/TbPmsUser.hbm.xml</value>             
 43             </list>
 44          </property>
 45          <property name="hibernateProperties">
 46             <props>
 47                <prop key="hibernate.dialect">
 48                      org.hibernate.dialect.MySQLDialect
 49                </prop>
 50                <prop key="hibernate.show_sql">true</prop>
 51             </props>
 52          </property>
 53         </bean>
 54      <!-- spring jdbcTemplate -->     
 55     <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">    
 56         <property name="dataSource" ref="dataSource"></property>    
 57     </bean>
 58     
 59     <!-- 事务管理器 -->
 60     <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
 61       <property name="sessionFactory">
 62            <ref local="sessionFactory" />
 63       </property>
 64     </bean>
 65     <!-- 事务代理拦截器的配置 -->
 66     <bean id="baseTransactionProxy" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
 67       <property name="transactionManager">
 68            <ref bean="transactionManager" />
 69       </property>
 70     <property name="transactionAttributes">
 71     <props>
 72     <prop key="insert*">PROPAGATION_REQUIRED</prop>
 73     <prop key="update*">PROPAGATION_REQUIRED</prop>
 74     <prop key="delete*">PROPAGATION_REQUIRED</prop>
 75     <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
 76     </props>
 77     </property>
 78     </bean>
 79     
 80     <!-- 日志bean 
 81     <bean id="logSupport" class="com.shproject.log.impl.LogSupportImpl"/>
 82     
 83     
 84     <aop:config>
 85       <aop:aspect id="addLog" ref="logSupport">
 86         <aop:pointcut id="servicePointCut" expression="execution(* com.shproject.service.impl.*.* (..))"/>
 87         <aop:after method="addLog" pointcut-ref="servicePointCut"/>
 88       </aop:aspect>
 89     </aop:config>
 90     -->
 91     <bean id="baseDao" class="com.pms.base.BaseDao">
 92        <property name="sessionFactory">
 93          <ref bean="sessionFactory"/>
 94       </property>
 95       <property name="jdbcTemplate">
 96          <ref bean="jdbcTemplate"/>
 97       </property>
 98     </bean>
 99     
100     
101     
102     <bean id="userDao" class="com.pms.dao.impl.TbPmsUserDaoImpl" parent="baseDao">        
103     </bean>
104     
105     <bean id="groupDao" class="com.pms.dao.impl.TbPmsGroupDaoImpl" parent="baseDao">        
106     </bean>
107     
108     
109     <bean id="userService" class="com.pms.service.impl.UserServiceImpl">
110       <property name="userDao">
111          <ref bean="userDao"/>
112       </property>
113     </bean>
114     
115     <bean id="groupService" class="com.pms.service.impl.GroupServiceImpl">
116       <property name="groupDao">
117          <ref bean="groupDao"/>
118       </property>
119     </bean>
120          
121 </beans>  
View Code

实体类及映射文件:

TbPmsUser.hbm.xml

 1 <?xml version="1.0"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 4 <!-- Generated 2013-7-22 10:23:27 by Hibernate Tools 3.2.4.GA -->
 5 <hibernate-mapping>
 6     <class name="com.pms.entity.TbPmsUser" table="tb_pms_user">
 7            <id name="userid" type="string" column="F_USERID">
 8                  <generator class="uuid.hex" /> 
 9            </id>
10             <property name="name" type="string" column="F_NAME">
11             
12             </property>
13             <property name="email" type="string" column="F_EMAIL">
14           
15             </property>
16             <property name="mobile" type="string" column="F_MOBILE">
17              
18             </property>
19             <property name="password" type="string" column="F_PASSWORD">
20                 
21             </property>
22             <property name="flag" type="java.lang.Integer" column="F_FLAG">
23              
24             </property>
25             <property name="registertime" type="date" column="F_REGISTERTIME">
26                 
27             </property>
28             <property name="lastlogin" type="date" column="F_LASTLOGIN">
29                 
30             </property>
31             <property name="areaid" type="string" column="F_AREAID">
32                 
33             </property>
34             <property name="levelId" type="java.lang.Integer" column="F_LEVEL_ID">
35                
36             </property>
37             <property name="hostid" type="string" column="F_HOSTID">
38                
39             </property>
40             <property name="islock" type="java.lang.Integer" column="F_ISLOCK">
41                 
42             </property>
43             <property name="lockdatebegin" type="date" column="F_LOCKDATEBEGIN">
44               
45             </property>
46             <property name="ifSuperuser" type="string" column="IF_SUPERUSER">
47                
48             </property>
49             <property name="lastmodify" type="date" column="F_LASTMODIFY">
50                
51             </property>
52             
53             <set name="groups" table="tb_pms_user_group" cascade="none" inverse="false">
54                 <key column="F_USERID"/>
55                 <many-to-many column="F_GROUPID" class="com.pms.entity.TbPmsGroup"/>               
56             </set>
57     </class>
58 </hibernate-mapping>
View Code

TbPmsGroup.hbm.xml

 1 <?xml version="1.0"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 4 <!-- Generated 2013-7-22 10:23:27 by Hibernate Tools 3.2.4.GA -->
 5 <hibernate-mapping>
 6     <class name="com.pms.entity.TbPmsGroup" table="tb_pms_group">      
 7             <id name="groupid" type="string" column="F_GROUPID">             
 8                 <generator class="uuid.hex" /> 
 9             </id>
10             <property name="groupname" type="string" column="F_GROUPNAME">
11             </property>
12             <property name="flag" type="java.lang.Integer" column="F_FLAG">
13             </property>
14             <property name="areaId" type="string" column="F_AREA_ID">
15             </property>
16             <property name="groupdesc" type="string" column="F_GROUPDESC">              
17             </property>
18             
19             <set name="users" table="tb_pms_user_group" lazy="true" inverse="false" cascade="none">
20                 <key column="F_GROUPID"/>
21                 <many-to-many column="F_USERID" class="com.pms.entity.TbPmsUser"/>
22             </set>
23 
24     </class>
25 </hibernate-mapping>
View Code

关于casecad

      cascade属性并不是多对多关系一定要用的,有了它只是让我们在插入或删除对像时更方便一些,只要在cascade的源头上插入或是删除,所有 cascade的关系就会被自己动的插入或是删除。便是为了能正确的cascade,unsaved-value是个很重要的属性。Hibernate通 过这个属性来判断一个对象应该save还是update,如果这个对象的id是unsaved-value的话,那说明这个对象不是 persistence object要save(insert);如果id是非unsaved-value的话,那说明这个对象是persistence object(数据库中已存在),只要update就行了。saveOrUpdate方法用的也是这个机制。

关于inverse

       inverse属性主要是用来说明两个模型间的关系究竟该怎么维护的,为true时说明两者的关系由对方去维护,为false时说明关系由自己维护,默认是false的,就是说关系的两端都来维护关系。这个意思就是说,如有一个Student,Teacher和TeacherStudent表,Student和Teacher是多对多对多关系,这个关系由TeacherStudent这个表来表现。那么什么时候插入或删除TeacherStudent表中的记录来维护关系呢?在用hibernate时,我们不会显示的对TeacherStudent表做操作。对TeacherStudent的操作是hibernate帮我们做的。hibernate就是看hbm文件中指定的是"谁"维护关系,那个在插入或删除"谁"时,就会处发对关系表的操作。前提是"谁"这个对象已经知道这个关系了,就是说关系另一头的对象已经set或是add到"谁"这个对象里来了。前面说过inverse默认是false,就是关系的两端都维护关系,对其中任一个操作都会处发对表系表的操作。当在关系的一头,如Student中的bag或set中用了inverse="true"时,那就代表关系是由另一关维护的(Teacher)。就是说当这插入Student时,不会操作TeacherStudent表,即使Student已经知道了关系。只有当Teacher插入或删除时才会处发对关系表的操作。所以,当关系的两头都用inverse="true"是不对的,就会导致任何操作都不处发对关系表的操作。当两端都是inverse="false"或是default值是,在代码对关系显示的维护也是不对的,会导致在关系表中插入两次关系。 

在一对多关系中inverse就更有意义了。在多对多中,在哪端inverse="true"效果差不多(在效率上)。但是在一对多中,如果要一方维护关 系,就会使在插入或是删除"一"方时去update"多"方的每一个与这个"一"的对象有关系的对象。而如果让"多"方面维护关系时就不会有update 操作,因为关系就是在多方的对象中的,直指插入或是删除多方对象就行了。当然这时也要遍历"多"方的每一个对象显示的操作修关系的变化体现到DB中。不管 怎样说,还是让"多"方维护关系更直观一些。

(1)对one-to-many而言,改变set,会让hibernate执行一系列的update语句, 不会delete/insert数据

(2)对many-to-many而言,改变set,只修改关系表的数据,不会影响many-to-many的另一方。

(3)虽然one-to-many和many-to-many的数据库操作不一样,但目的都是一个:维护数据的一致性。

 

 

另记:在进行Delete和updete操作时,要先把对象get出来使其从脱管态转到持久态,这样才能对其进行操作。

原文地址:https://www.cnblogs.com/angryprogrammer/p/3217592.html