`
yezi
  • 浏览: 276227 次
  • 来自: 北京
社区版块
存档分类
最新评论

关于多对多关系的hibernate实现例子

阅读更多
通过一个简单的例子描述一下在hibernate中如何实现多对多的关系。
系统环境:Webwork + spring + hibernate

逻辑描述:实现一个用户(User)和组(Group)的逻辑关系。系统中的用户可以自行创建组,同时每个组中可以添加不同的成员。这个环境是一个典型的多对多的关系,唯一的一个区别是,每个组是有从属的,也是说每个组隶属于一个用户,在这一点上是一个一对多的关系。

系统目标,可以灵活创建用户、组,同时组中可以添加用户。

数据库表:User(用户表)、groups(用户组),用过powerdesign可以设计一个数据逻辑模型,将其转化为屋里模型后,实际我们可以看到,系统自动创建了另外一个表,就是usergroups,在这张表中记录的是user和groups的对应关系。为了表明group的从属关系,我们在group中定义一个字段ownerid,然后通过一对多的关系来描述用户和组之间的关系。
user:
create table user
(
   id                   varchar(32) not null,
   email                varchar(100) not null,
   username             varchar(50) not null
);

groups:
create table groups
(
   id                   varchar(32) not null,
   ownerid              varchar(32) not null,
   name                 varchar(100) not null
);
usergroups
create table usergroups
(
   userid               varchar(32) not null,
   groupid              varchar(32) not null
);
alter table groups add constraint FK_Reference_3 foreign key (ownerid)
      references user (id) on delete restrict on update restrict;

alter table usergroups add constraint FK_Reference_1 foreign key (userid)
      references user (id) on delete cascade on update cascade;

alter table usergroups add constraint FK_Reference_2 foreign key (groupid)
      references groups (id) on delete cascade on update cascade;


hibernate实现:
对于hibernate的实现,我们可以通过hibernate的工具来生成基本的映射文件和bean,但是在这里面需要注意以下一些问题:
1、对于saveOrUpdate的设置:当DAO更新数据库的时候,我们可以采用save、update两种方式去区分insert、update两种数据库操作,当然一种更方便的方法是调用HibernateTemplate.saveOrUpdate()通用方法,系统将根据主键来判断是insert操作,还是update操作。这时候就要在bean的映射文件中表明,否则系统将无法正确处理。例如User.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- 
    Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
    <class name="com.example.dao.model.User" table="user" catalog="many" >
        <id name="id" type="java.lang.String" unsaved-value="null">
            <column name="id" length="32" />
            <generator class="uuid.hex"></generator>
        </id>
        <property name="email" type="java.lang.String">
            <column name="email" length="100" not-null="true" />
        </property>
        <property name="username" type="java.lang.String">
            <column name="username" length="50" not-null="true" />
        </property>
        <set name="groupses" table="usergroups" catalog="many" cascade="none" lazy="true">
            <key>
                <column name="userid" length="32" not-null="true" />
            </key>
            <many-to-many entity-name="com.example.dao.model.Groups">
                <column name="groupid" length="32" not-null="true" />
            </many-to-many>
        </set>
        <set name="ownergroupses" inverse="true" cascade="delete" lazy="true" order-by="createtime desc">
            <key>
                <column name="ownerid" length="32" not-null="true" unique="false" />
            </key>
            <one-to-many class="com.example.dao.model.Groups" />
        </set>
    </class>
</hibernate-mapping>

在xml中我们可以看到,id设置了unsaved-value="null",这样系统就会通过对象的id来决定是insert还是update,如果user的id为null,那么系统将按照insert处理,反之将按照update处理。这里有个注意的问题,当使用BeanUtils来转换formbean到bean的时候,将把null值处理为“”,这样系统在保存的时候,认为id不是null,数据库将进行update处理,就会出现错误,这时就要求我们强制设置一下,保证系统的正确处理
2、关于lazy=true(延迟加载)的使用
在使用hibernate时,如果碰到一对一、一对多、多对多的关系,经常需要使用延迟加载来提高系统的性能,否则每次系统调用一个bean的时候都需要将关联的对象也同时load出来,系统的效能是很低的。hibernate通过延迟加载的方法来提高性能。但是如果我们通过spring来管理系统里面的bean,就会遭遇到一个常见的问题,就是当使用了延迟加载后,我们如果在load一个对象后,还需要load关联的对象,系统经常会抛出session已经关闭的异常,这时候就需要使用OpenSessionInView来延缓session关闭的时间,系统将在request完全load结束后关闭session。着也随之带来一个问题,如果用户网络状况比较差的情况下,request load的时间会非常长,就会造成session迟迟不能关闭,那么就会保持一个很长的Connection,当访问量增大的时候,就会造成系统性能下降(数据连接池中链接迟迟不能回收)。解决这一问题的办法是使用aop的拦截器,来处理这种延迟加载。但方法相对比较复杂。就目前的情况来讲,暂时使用OpenSessionInView是一个折衷的办法,其具体配置如下,在需要延迟加载的hbm.xml中设置lazy=true,然后在web.xml中添加OpenSessionInView:
<filter>
		<filter-name>opensession</filter-name>
		<filter-class>
			org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
		</filter-class>
		<init-param>
			<param-name>sessionFactoryBeanName</param-name>
			<param-value>mySessionFactory</param-value> 
		</init-param>
	</filter>
	<filter-mapping>
	  <filter-name>opensession</filter-name>
	  <url-pattern>*.do</url-pattern> 
	</filter-mapping>

这里注意不要在filter中设置singleSession=false,否则会造成多session的异常
3、关于inverse,cascade的设置
对于hibernate中inverse的设置,实际是表明哪一端对系统数据发生的变化不做处理,也就是谁来维护关系。例如本例中user和group,usergroups是user和group的对应关系,从实际上来讲,当组被删除时,用户和组的关系发生变化,那么实际应该是groups来维护usergroups的关系,也就应该在user.hbm.xml设置为inverse=true,这样关系就交有groups来维护了。
对于cascade,实际标识的是级联的操作,例如user删除的时候,实际需要将groups中相应的组删除,那么这里就需要在user.hbm.xml中标识cascade="delete"
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics