hibernate学习_关联映射
1.多对一(单向)关联映射(员工表-部门表):
员工类:
package com.xudong.po;
public class Employee {
private int id;
private String name;
private Department department;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
}
部门类:
package com.xudong.po;
public class Department {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
hibernate.cfg.xml:
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.url">jdbc:mysql:///test</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="dialect">
org.hibernate.dialect.MySQL5Dialect
</property>
<property name="format_sql">true</property>
<property name="current_session_context_class">thread</property>
<mapping resource="com/xudong/po/Item.hbm.xml" />
</session-factory>
</hibernate-configuration>
对象关系映射文件(Item.hbm.xml):
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping
package="com.xudong.po">
<class name="Department" table="t_dept">
<id name="id">
<generator class="native"/>
</id>
<property name="name"></property>
</class>
<class name="Employee" table="t_emp">
<id name="id">
<generator class="native"/>
</id>
<property name="name"></property>
<many-to-one name="department"></many-to-one>
</class>
</hibernate-mapping>
重点:<many-to-one name=""/>标签
创建表的工具类:
package com.xudong.hibernate.util;
import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
public class Hbm2ddlUtil {
public static void main(String[] args) {
Configuration cfg = new Configuration().configure();
SchemaExport se = new SchemaExport(cfg);
se.create(true, true);
}
}
运行后产生的sql:
alter table t_emp
drop
foreign key FK68F5E7D76166533
drop table if exists t_dept
drop table if exists t_emp
create table t_dept (
id integer not null auto_increment,
name varchar(255),
primary key (id)
)
create table t_emp (
id integer not null auto_increment,
name varchar(255),
department integer,
primary key (id)
)
alter table t_emp
add index FK68F5E7D76166533 (department),
add constraint FK68F5E7D76166533
foreign key (department)
references t_dept (id)
往两张表中添加数据:
package com.xudong.hibernate.test;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.xudong.hibernate.util.HibernateUtil;
import com.xudong.po.Department;
import com.xudong.po.Employee;
public class T {
public static void main(String[] args) {
Session session = null;
Transaction ts = null;
try {
session = HibernateUtil.getSession();
ts = session.beginTransaction();
Department department = new Department();
department.setName("HR");
Employee employee = new Employee();
employee.setName("alice");
employee.setDepartment(department);
session.save(department);
session.save(employee);
System.out.println(employee.getDepartment().getName());
ts.commit();
} catch (HibernateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
ts.rollback();
}
}
}
生成的sql:
Hibernate:
insert
into
t_dept
(name)
values
(?)
Hibernate:
insert
into
t_emp
(name, department)
values
(?, ?)
HR
上面打印出的部门名称即是添加到t_dept表中的部门名称,我们用了这样一段代码 System.out.println(employee.getDepartment().getName());把它拿出来,内部实现机制是,先查到部门的id,再通过标签<many-to-one name="department"/>映射到Department类,通过部门id拿出满足条件的Department,再拿出部门类的名称。
在上面的两条语句中session.save(department); session.save(employee); 如果不写前一句,直接写后一句,由于先有部门再有员工,此时会报一个异常,注意到此时是一个多对一关系,倘若在多的一方,表现在映射文件上就是标签里的属性(cascade="save-update")<many-to-one name="department" cascade="save-update"/>,现在再运行就没有错误了,会自动级联创建表t_dept;
2.一对多(单向)关联映射(员工表与部门表):
package com.xudong.po;
public class Employee {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
部门表:
package com.xudong.po;
import java.util.Set;
public class Department {
private int id;
private String name;
//之所以用Set,因为Set集合是唯一的
private Set<Employee> emps;
public Set<Employee> getEmps() {
return emps;
}
public void setEmps(Set<Employee> emps) {
this.emps = emps;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
对象关系映射文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.xudong.po">
<class name="Employee" table="t_emp">
<id name="id">
<generator class="native" />
</id>
<property name="name"></property>
</class>
<class name="Department" table="t_dept">
<id name="id">
<generator class="native" />
</id>
<property name="name"></property>
<set name="emps">
<key column="dept_id"></key>
<one-to-many class="Employee" />
</set>
</class>
</hibernate-mapping>
创建表产生的sql:
alter table t_emp
drop
foreign key FK68F5E7DA0313336
drop table if exists t_dept
drop table if exists t_emp
create table t_dept (
id integer not null auto_increment,
name varchar(255),
primary key (id)
)
create table t_emp (
id integer not null auto_increment,
name varchar(255),
dept_id integer,
primary key (id)
)
alter table t_emp
add index FK68F5E7DA0313336 (dept_id),
add constraint FK68F5E7DA0313336
foreign key (dept_id)
references t_dept (id)
添加元素到数据表中:
package com.xudong.hibernate.test;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.xudong.hibernate.util.HibernateUtil;
import com.xudong.po.Department;
import com.xudong.po.Employee;
public class T {
public static void main(String[] args) {
Session session = null;
Transaction ts = null;
try {
session = HibernateUtil.getSession();
ts = session.beginTransaction();
Department department = new Department();
department.setName("HR");
Employee employee1 = new Employee();
employee1.setName("smith");
Employee employee2 = new Employee();
employee2.setName("jerry");
Set<Employee> sets = new HashSet<Employee>();
sets.add(employee1);
sets.add(employee2);
department.setEmps(sets);
session.save(employee1);
session.save(employee2);
session.save(department);
ts.commit();
} catch (HibernateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
ts.rollback();
}
}
}
此时产生的sql:
Hibernate:
insert
into
t_emp
(name)
values
(?)
Hibernate:
insert
into
t_emp
(name)
values
(?)
Hibernate:
insert
into
t_dept
(name)
values
(?)
Hibernate:
update
t_emp
set
dept_id=?
where
id=?
Hibernate:
update
t_emp
set
dept_id=?
where
id=?
这里为什么产生了两条update语句呢?
在上面这段代码中,我们首先保存的是员工表的数据,由于此时部门表的信息尚未保存,在员工表中有一个字段名为dept_id暂且被赋值为null,当保存完员工表的信息后,部门表信息被保存,这时就有了dept_id,hibernate就会自动对上面员工表的信息(dept_id)进行更新!!!
->缺点:产生了多余的update语句(在少的一端进行维护);
当代码变为在多的一端进行维护时,即将代码改为 session.save(department); session.save(employee1); session.save(employee2);就不会产生多余的update语句。
此处映射文件中的<key column="dept_id"></key>,是在另一张表中添加外键dept_id;
此外在<set>标签里有一项属性“inverse = true" ,这个属性不管代码是在多的一端或者在少的一端进行维护,都会反转到多的一端,不会产生额外的update语句。
产生的sql:
Hibernate:
insert
into
t_emp
(name)
values
(?)
Hibernate:
insert
into
t_emp
(name)
values
(?)
Hibernate:
insert
into
t_dept
(name)
values
(?)
3.一对一主键关联映射[双向](wife表与husband表):
Wife类:
package com.xudong.po;
public class Wife {
private int id;
private String name;
private Husband husband;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Husband getHusband() {
return husband;
}
public void setHusband(Husband husband) {
this.husband = husband;
}
}
Husband类:
package com.xudong.po;
public class Husband {
private int id;
private String name;
private Wife wife;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Wife getWife() {
return wife;
}
public void setWife(Wife wife) {
this.wife = wife;
}
}
对象关联映射文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.xudong.po">
<class name="Husband" table="t_hbd">
<id name="id" column="hid">
<generator class="foreign">
<param name="property">Wife</param>
</generator>
</id>
<property name="name"></property>
<one-to-one name="wife" class="Wife" constrained="true"></one-to-one>
</class>
<class name="Wife" table="t_wife">
<id name="id" column="wid">
<generator class="native" />
</id>
<property name="name"></property>
<one-to-one name="husband" class="Husband"></one-to-one>
</class>
</hibernate-mapping>
创建表生成的sql:
alter table t_hbd
drop
foreign key FK68F685FCF6371FB
drop table if exists t_hbd
drop table if exists t_wife
create table t_hbd (
id integer not null,
name varchar(255),
primary key (id)
)
create table t_wife (
id integer not null auto_increment,
name varchar(255),
primary key (id)
)
alter table t_hbd
add index FK68F685FCF6371FB (id),
add constraint FK68F685FCF6371FB
foreign key (id)
references t_wife (id)
通过Wife类查询Husband类里的name属性名:
package com.xudong.hibernate.test;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.xudong.hibernate.util.HibernateUtil;
import com.xudong.po.Husband;
import com.xudong.po.Wife;
public class T {
public static void main(String[] args) {
add();
query(1);
}
static void add() {
Session session = null;
Transaction ts = null;
try {
session = HibernateUtil.getSession();
ts = session.beginTransaction();
Wife wife = new Wife();
wife.setName("alice");
Husband hbd = new Husband();
hbd.setName("jack");
hbd.setWife(wife);
wife.setHusband(hbd);
session.save(wife);
session.save(hbd);
ts.commit();
} catch (HibernateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
ts.rollback();
}
}
static void query(int id) {
Session session = null;
Transaction ts = null;
try {
session = HibernateUtil.getSession();
ts = session.beginTransaction();
Wife wife = (Wife) session.get(Wife.class, id);
System.out.println(wife);
System.out.println(wife.getHusband().getName());
// Husband hbd = (Husband)session.get(Husband.class,id);
// System.out.println(hbd.getWife().getName());
ts.commit();
} catch (HibernateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
ts.rollback();
}
}
}
运行结果:
Hibernate:
insert
into
t_wife
(name)
values
(?)
Hibernate:
insert
into
t_hbd
(name, id)
values
(?, ?)
Hibernate:
select
wife0_.id as id1_1_,
wife0_.name as name1_1_,
husband1_.id as id0_0_,
husband1_.name as name0_0_
from
t_wife wife0_
left outer join
t_hbd husband1_
on wife0_.id=husband1_.id
where
wife0_.id=?
com.xudong.po.Wife@1e879e
//查询出的Husband名称jack
jack
通过Husband类查询Wife类里的name属性名:
static void query(int id) {
Session session = null;
Transaction ts = null;
try {
session = HibernateUtil.getSession();
ts = session.beginTransaction();
Husband husband = (Husband)session.get(Husband.class,id);
System.out.println(husband.getWife().getName());
// Husband hbd = (Husband)session.get(Husband.class,id);
// System.out.println(hbd.getWife().getName());
ts.commit();
} catch (HibernateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
ts.rollback();
}
}
运行结果:
Hibernate:
select
husband0_.id as id0_0_,
husband0_.name as name0_0_
from
t_hbd husband0_
where
husband0_.id=?
Hibernate:
select
wife0_.id as id1_1_,
wife0_.name as name1_1_,
husband1_.id as id0_0_,
husband1_.name as name0_0_
from
t_wife wife0_
left outer join
t_hbd husband1_
on wife0_.id=husband1_.id
where
wife0_.id=?
alice
constrained属性只能在<one-to-one>标签中使用,如果constrained="true"表明当前这张表有外键与关联表相对应;
标签<generator>里的class="foreign",表明当前这张表的主键不是自动生成的,而是依靠另一张表的主键生成的,其中在此标签内有<param name="property"></param>标签,这里面的值代表了当前表的主键依赖于哪个类生成(对应于数据库中哪个表生成);
4.一对一外键关联映射(双向):
对象关联映射文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.xudong.po">
<class name="Husband" table="t_hbd">
<id name="id">
<generator class="native"></generator>
</id>
<property name="name"></property>
<one-to-one name="wife" property-ref="husband"></one-to-one>
</class>
<class name="Wife" table="t_wife">
<id name="id">
<generator class="native" />
</id>
<property name="name"></property>
<many-to-one name="husband" column="hid" unique="true"></many-to-one>
</class>
</hibernate-mapping>
<one-to-one name="wife" property-ref="husband"></one-to-one>标签中的property-ref属性用来指明关联类的一个属性,与关联表的外键相对应;
5.多对多关联映射(Teacher与Student):
Teacher类:
package com.xudong.po;
import java.util.Set;
public class Teacher {
private int id;
private String name;
private Set<Student> students;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}
Student类:
package com.xudong.po;
import java.util.Set;
public class Student {
private int id;
private String name;
private Set<Teacher> teachers;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Teacher> getTeachers() {
return teachers;
}
public void setTeachers(Set<Teacher> teachers) {
this.teachers = teachers;
}
}
对象关联映射文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.xudong.po">
<class name="Teacher" table="t_teacher">
<id name="id">
<generator class="native"></generator>
</id>
<property name="name"></property>
<set name="students" table="teacher_student">
<key column="tid"></key>
<many-to-many class="Student" column="sid"></many-to-many>
</set>
</class>
<class name="Student" table="t_student">
<id name="id">
<generator class="native" />
</id>
<property name="name"></property>
<set name="teachers" table="teacher_student" inverse="true">
<key column="sid"></key>
<many-to-many class="Teacher" column="tid"></many-to-many>
</set>
</class>
</hibernate-mapping>
创建表生成的sql:
alter table teacher_student
drop
foreign key FK2E2EF2DE3F9A82DA
alter table teacher_student
drop
foreign key FK2E2EF2DE59CDD042
drop table if exists t_student
drop table if exists t_teacher
drop table if exists teacher_student
create table t_student (
id integer not null auto_increment,
name varchar(255),
primary key (id)
)
create table t_teacher (
id integer not null auto_increment,
name varchar(255),
primary key (id)
)
create table teacher_student (
tid integer not null,
sid integer not null,
primary key (sid, tid)
)
alter table teacher_student
add index FK2E2EF2DE3F9A82DA (sid),
add constraint FK2E2EF2DE3F9A82DA
foreign key (sid)
references t_student (id)
alter table teacher_student
add index FK2E2EF2DE59CDD042 (tid),
add constraint FK2E2EF2DE59CDD042
foreign key (tid)
references t_teacher (id)
多对多关联映射需要创建中间表,标签<set>中的属性table用来指明中间表的名称,两次指明的表名称要相同,标签<key>用来指明需要在中间表里设置的外键名称;
向表中添加数据:
package com.xudong.hibernate.test;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.xudong.hibernate.util.HibernateUtil;
import com.xudong.po.Student;
import com.xudong.po.Teacher;
public class T {
public static void main(String[] args) {
add();
}
static void add() {
Session session = null;
Transaction ts = null;
try {
session = HibernateUtil.getSession();
ts = session.beginTransaction();
Set<Teacher> sets = new HashSet<Teacher>();
Teacher t1 = new Teacher();
t1.setName("t1");
sets.add(t1);
Teacher t2 = new Teacher();
t2.setName("t2");
sets.add(t2);
Set<Student> sets1 = new HashSet<Student>();
Student s1 = new Student();
s1.setName("s1");
sets1.add(s1);
Student s2 = new Student();
s2.setName("s2");
sets1.add(s2);
t1.setStudents(sets1);
t2.setStudents(sets1);
session.save(s1);
session.save(s2);
session.save(t1);
session.save(t2);
ts.commit();
} catch (HibernateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
ts.rollback();
}
}
}
mysql中的三张表:
其中映射文件里的<set>标签里有个属性inverse="true",是在Student类下设置的,表示关联关系由Teacher类来维护,只有当主控方对象状态发生改变时(这里指的就是Teacher类),hibernate会根据对象状态的改变来同步更新,即产生相应的sql语句;当代码执行到下面两句(t1.setStudents(sets1)、t2.setStudents(sets1))时,Teacher类的对象状态发生了改变,产生4条sql语句;如果inverse="true"这项属性写在Teacher类下,那么执行完插入数据的操作后,多对多关系的中间表里没有任何数据,因为Student的状态并未发生改变,hibernate就不会产生insert语句,来更新中间表;