Hibernate数据关联是在Hibernate容器映射技术之上发展起来的。
Hibernate数据关联分为如下三种:
一对一(1:1)一个人拥有唯一身份证号
一对多(1:N)一个部门有很多员工
多对多(M:N)一个学生可以选很多课程,一门课程也可以有多个学生
一对多关系很常见,例如班级与学生的关系就是典型的一对多的关系。在实际编写程序时,
一对多关系有两种实现方式:单向关联和双向关联。
单向的一对多关系只需要在一方进行映射配置,而双向的一对多需要在关联的双方进行映射配置.
下面以Group(班级)和Student(学生)为例讲解如何配置一对多的关系。
单向关联:
单向的一对多关系只需要在一方进行映射配置,所以我们只配置Group的映射文件: <hibernate-mapping>
<class name="hibernate.PO.Group" table="t_group" lazy="true">
<id name="id" type="java.lang.Integer">
<column name="id"/>
<generator class="increment"/>
</id>
<!-- insert属性表示被映射的字段是否出现在SQL的INSERT语句中 -->
<property name="name" type="java.lang.String" update="true" insert="true">
<column name="name" length="20" />
</property>
<!-- set元素描述的字段对应的类型为java.util.Set类型。
inverse用于表示双向关联中的被动一端。inverse的值
为false的一方负责维护关联关系。默认是false。
sort排序关系,其可选值为:unsorted(不排序)。
natural(自然排序)。
comparatorClass(由某个实现了java.util.comparator接口的类型指定排序算法。)
<key>子元素的column属性指定关联表(t_student表)的外键。
-->
<set name="students"
table="t_student"
lazy="true"
inverse="false"
cascade="all"
sort="unsorted">
<key column="ID"/>
<one-to-many class="hibernate.PO.TStudent"/>
</set>
</class>
</hibernate-mapping>
双向关联:
如果要设置一对多双向关联关系,那么还需要在“多”方的映射文件中使用<many-to-one>标记。
例如,在Group与Student一对多的双向关联中,除了Group的映射文件外还需要在Student的映射文件中加入如下代码:
<many-to-one name="group"
class="Group"
cascade="none"
outer-join="auto"
update="true"
insert="true"
column="ID" />
inert和update设定是否对column属性指定的关联字段进行insert和update操作。
也就是说被映射的字段是否出现在SQL的insert或update语句中。
此外将Group.hbm.xml中<set>元素的inverse设置为true.
还是举个实际例子吧:
先是数据库创建脚本:
-- 删除表
DROP TABLE person ;
DROP TABLE address ;
CREATE TABLE person
(
pid VARCHAR(32) NOT NULL PRIMARY KEY ,
name VARCHAR(20) NOT NULL ,
age INT
) ;
CREATE TABLE address
(
aid VARCHAR(32) NOT NULL PRIMARY KEY ,
name VARCHAR(50) NOT NULL ,
zipcode VARCHAR(10) NOT NULL ,
pid VARCHAR(32) ,
FOREIGN KEY (pid) REFERENCES person(pid) ON DELETE CASCADE
) ;
*****************************************************************
然后编写POJO类:
package wjr.hibernate.demo23_26.associated1N;
import java.util.Set;
public class Person {
private String pid;
private String name;
private int age;
private Set address;
。。。。。getter和setter方法。。。。
}
package wjr.hibernate.demo23_26.associated1N;
public class Address {
private String aid;
private String name;
private String zipcode;
private String pid;
private Person person;
。。。。。getter和setter方法。。。。
}
******************************************************************
生成和修改配置文件:
<class name="wjr.hibernate.demo23_26.associated1N.Person" table="person" catalog="test">
<id name="pid" type="java.lang.String">
<column name="pid" length="32" />
<generator class="uuid.hex"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name" length="20" not-null="true" />
</property>
<property name="age" type="java.lang.Integer">
<column name="age" />
</property>
<set name="address" inverse="true" cascade="all">
<key>
<column name="pid" length="32" unique="true" />
</key>
<one-to-many class="wjr.hibernate.demo23_26.associated1N.Address" />
</set><!--inverse="true"表示自动反转关联,也就是在插入数据时能自动将关联id插入数据库,
如果inverse="false",则在插入数据时,先插入,然后再更新关联数据,这样就多了
几条更新语句(插入几条记录就多几条更新语句),效率降低了-->
</class>
·····················
<class name="wjr.hibernate.demo23_26.associated1N.Address" table="address" catalog="test">
<id name="aid" type="java.lang.String">
<column name="aid" length="32" />
<generator class="uuid.hex"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name" length="50" not-null="true" />
</property>
<property name="zipcode" type="java.lang.String">
<column name="zipcode" length="10" not-null="true" />
</property>
<many-to-one name="person" class="wjr.hibernate.demo23_26.associated1N.Person" >
<column name="pid" length="32" />
</many-to-one>
</class>
*********************************************************
编写操作类:
package wjr.hibernate.demo23_26.associated1N;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
public class OperateTest {
Session session = null;
public OperateTest()
{
session = new Configuration().configure().buildSessionFactory().openSession() ;
}
public void insert(Person person)
{
this.session.save(person);
this.session.beginTransaction().commit();
}
public void update(Person person)
{
this.session.update(person);
this.session.beginTransaction().commit();
}
public void delete(String id)
{
String hql ="delete from Person where pid = ?";
Query q = this.session.createQuery(hql);
q.setString(0, id);
q.executeUpdate();
this.session.beginTransaction().commit();
}
public Person queryByName(String name) {
Person p = null;
String hql = "FROM Person AS p WHERE p.name=?";
Query q = this.session.createQuery(hql);
q.setString(0, name);
List all = q.list();
if (all.size() > 0) {
p = (Person) all.get(0);
}
return p;
}
}
*******************************************************************
最后写测试类:
package wjr.hibernate.demo23_26.associated1N;
public class TestRun {
public static void main(String[] args) {
//测试插入
// OperateTest test = new OperateTest();
// Person person = new Person();
// person.setName("wjr");
// person.setAge(25);
// //地址
// Address address = new Address();
// address.setName("双流");
// address.setPerson(person);
// address.setZipcode("610021");
//
// Set set = new TreeSet();
// set.add(address);
// person.setAddress(set);
// test.insert(person);
//测试update
OperateTest test = new OperateTest();
Person person = test.queryByName("wjr");
//增加地址
Address address = new Address();
address.setName("人民南路");
address.setPerson(person);
address.setZipcode("610041");
person.getAddress().add(address);
test.update(person);
}
}