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>
实体类及映射文件:
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>
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>
关于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出来使其从脱管态转到持久态,这样才能对其进行操作。