数据库表与表之间的关联关系,分为三种一对一、一对多、多对一、多对多。
在通常的数据库设计的时候一般都是通过表外键来建立各种关系,做这些关系一般都是为了一些级联操作。
由于Hibernate是把数据库中表与表之间的关系型数据映射成面向对象型的数据关系,在hibernate中,也做了相应的数据级联操作的工作。因而可以在数据层来完成数据库表的关联,可以在这一层通过面向对象的方式形象的完成级联操作,这时不需要在数据库表里建立复杂的外键关联也可以实现。
在网上和书上看到很多介绍这方面的知识,一般都是按照一对一、一对多、多对一、多对多的顺序介绍,为了容易理解,我通过另一种顺序:
一般多对多的实现都是通过第三个表来实现,在hibernate里也不例外,我们可以分析出这个第三方表与另外两个表就是多对一的关系。
一对一的关系可以看作是一对多的特殊情况。
一对多与多对一可以看作仅仅是方向的不同而已。
所以我先介绍一对多,然后 一对一,然后多对多。
一对多与多对一关联关系
在hibernate中关联关系一般都是通过外键来关联的,(我在学习的时候也有个错误的理解,这个外键不是在数据库表上建立的,经过试验在数据库中不建立外键关系,只在hibernate中设置完全可以实现同样的效果),这时的关联可以分为单向与双向两种。
所谓的单向就是说,在两端中的任一端不知知道另一端的存在,而另一端确清楚的小的另一端;双向当然就是双方互知了。
1、单向关联
在hibernate里面一对多关联关系的实现实在“一”的一段映射文件中使用<one-to-many>节点实现的,同时要求在“一”端的POJO使用集合来存储“多段”的对象。
在以下例子中我将实现一个留言板程序。
先完成数据库的一部分设计,首先需要一个表来存储用户信息,然后还需要一个表来存放留言信息,具体的SQL语句如下(我采用的是MySQL数据库):
CREATE TABLE `user` (
`usr_id` int(11) NOT NULL auto_increment,
`usr_name` char(20) default NULL,
`usr_psw` char(20) default NULL,
PRIMARY KEY (`usr_id`)
) ENGINE=InnoDB DEFAULT CHARSET=UTF8;
CREATE TABLE `message` (
`msg_id` int(11) NOT NULL auto_increment,
`msg_ttl` char(20) NOT NULL default 0,
`msg_desc` char(50) default NULL,
`msg_date` Date,
`usr_id` int(11)NOT NULL default 0,
PRIMARY KEY (`msg_id`)
) ENGINE=InnoDB DEFAULT CHARSET=UTF8;
显然这是个一对多的例子,相应的POJO类为
public class Message {
private int msgId;
private String ttl;
private String desc;
private Date date;
public class UserInfo {
private int userId;
private String name;
private String password;
private IdCard idCard;
private Set messages;
这里我省了get,set方法
相应的映射文件配置:
<hibernate-mapping>
<class name="xiaojin.hibernate.entity.UserInfo" table="USER">
<id name="userId" type="int" column="usr_id">
<generator class="native"/>
</id>
<property name="name" column="usr_name" type="string" />
<property name="password" column="usr_psw" type="string" />
<set name="messages" order-by="usr_id" cascade="all">
<key column="usr_id" />
<one-to-many class="xiaojin.hibernate.entity.Message" />
</set>
</class>
</hibernate-mapping>
这个配置文件最主要的就是这个节点
<set name="messages" order-by="usr_id" cascade="all">
<key column="usr_id" />
<one-to-many class="xiaojin.hibernate.entity.Message" />
</set>
这个<set>节点意味着POJO UserInfo类里面定义一个集合,在这个节点中:
<key>:指定多端的外键,与一端的主键相关联,即MESSAGE表中的usr_id
<one-to-many>:指定多端的对应的类
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="xiaojin.hibernate.entity.Message" table="MESSAGE">
<id name="msgId" type="int" column="msg_id">
<generator class="native"/>
</id>
<property name="ttl" column="msg_ttl" type="string" not-null="true"/>
<property name="desc" column="msg_desc" type="string" not-null="true"/>
<property name="date" column="msg_date" type="string" />
多对一的映射与上面完全一样,只不过需要在多的一段进行配置,即在message的应射文件中需要配置<many-to-one>节点:
<many-to-one name="user" column="usr_id" />