通过一个简单的例子描述一下在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"
分享到:
相关推荐
hibernate例子(多对一)hibernate例子(多对一)hibernate例子(多对一)hibernate例子(多对一)hibernate例子(多对一)
Hibernate一对一,一对多,多对多例子,讲的非常清楚
这个例子会让你很快明白hibernate多对多的原理以及所涉及的程序源码,相信你会有很大的感触!
在hibernate中,通常配置对象关系映射关系有两种,一种是基于xml的方式,另一种是基于annotation的注解方式,熟话说,萝卜青菜,可有所爱,每个人都有自己喜欢的配置方式,这个是xml配置的例子
hibernate一对多例子 一对多关联 通过外键 连接两个类对应的表,而没有中间集合表。 这个关系模型失去了一些Java集合的语义: 一个被包含的实体的实例只能被包含在一个集合的实例中 一个被包含的实体的实例只能...
博文链接:https://davexin.iteye.com/blog/102726
是个hibernate 一对一,一对多,多对多 例子,包含了jar包,单元测试,mysql数据库脚本。供初学者学习,需要的下吧
包含《多对多双向关联映射》《多对一单向关联映射》《多对一双向关联映射》《一对多单向关联映射》等文档,并有图解及例子,非常适合新手学习,尤其是刚刚接触hibernate,对映射关系不清楚的。。。。
在hibernate中,通常配置对象关系映射关系有两种,一种是基于xml的方式,另一种是基于annotation的注解方式,熟话说,萝卜青菜,可有所爱,每个人都有自己喜欢的配置方式,我在试了这两种方式以后,发现使用...
hibernate双向一对多增删查改的例子
hibernate 一对多 多对多 四个例子
这个例子会让你很快懂得hibernate一对多的映射机制,你看了以后会有很大的感触!
hibernate实现一对多例子
使用hibernate技术实现对MySQL数据库的一对多和多对一的映射。下载后对应着改一下自己的IP地址就好了。
使用Hibernate 做的Many_to_many例子,保证可以运行的哦~
基于HIBERNATE 操作表的关系练习例子
这个是一个简单的实现manytomany的例子,这样可以实现数据库中多对多的关系 这个项目演示了如何配置多对多,使多对多的关系很明朗。
HIbernate与oracle数据库应用例子
NULL 博文链接:https://chaoyi.iteye.com/blog/2148992