一、一对多
Dempartment {
private int id;
private String name;
private Set<Employee> employees = new HashSet<Employee>();
}
Employee {
private int id;
private String name;
private Dempartment department;
}
---Employee.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="pde.ams.onetomany">
<class name="Employee" table="employee">
<id name="id">
<generator class="native" />
</id>
<property name="name"></property>
<many-to-one name="department" column="departmentId" class="Dempartment"></many-to-one>
</class>
</hibernate-mapping>
---Dempartment.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="pde.ams.onetomany">
<class name="Dempartment" table="dempartment">
<id name="id">
<generator class="native" />
</id>
<property name="name"></property>
<!-- employees属性 是Employees对象 Dempartment与Employees的一对多的关系 -->
<set name="employees">
<key column="departmentId"></key>
<one-to-many class="Employee"/>
</set>
</class>
</hibernate-mapping>
package pde.ams.onetomany;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
/**
* @author 作者 macx:
* @version 创建时间:2018年4月29日 下午1:40:06 类说明
*/
public class App {
private static SessionFactory sessionFactory = new Configuration()//
.configure()//
.addClass(Dempartment.class)// 加载指定类对应的映射文件(以类名为前缀,后缀为.hbm.xml的同一个包下的文件)
.addClass(Employee.class)// 加载指定类对应的映射文件(以类名为前缀,后缀为.hbm.xml的同一个包下的文件)
.buildSessionFactory();
@Test
public void saveUser() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// ---------------------------------------
// 创建对象
Dempartment department = new Dempartment();
department.setName("开发部1");
Employee employee1 = new Employee();
employee1.setName("张三");
Employee employee2 = new Employee();
employee2.setName("李四");
// 关联起来
employee1.setDepartment(department);
employee2.setDepartment(department);
department.getEmployees().add(employee1);
department.getEmployees().add(employee2);
// 保存
session.save(department); // 保存部门
session.save(employee1);
session.save(employee2);
// ---------------------------------------
session.getTransaction().commit();
session.close();
}
@Test
public void getUser() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// ---------------------------------------
// 获取部门,并显示关联的员工信息
Dempartment department = (Dempartment) session.get(Dempartment.class, 29);
System.out.println("部门名称:" + department.getName());
System.out.println("关联的员工:" + department.getEmployees());
// // 获取员工,并显示关联的部门信息
Employee employee = (Employee) session.get(Employee.class, 1);
System.out.println("员工姓名:" + employee.getName());
System.out.println("所属的部门:" + employee.getDepartment());
// ---------------------------------------
session.getTransaction().commit();
session.close();
}
// 移除关联关系
@Test
public void testRemoveRelation() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// ---------------------------------------
// // 让员工不再属于原部门
// Employee employee = (Employee) session.get(Employee.class, 1);
// employee.setDepartment(null);
// 让Department不与任何Employee关联
Dempartment department = (Dempartment) session.get(Dempartment.class, 26);
department.getEmployees().clear();
// ---------------------------------------
session.getTransaction().commit();
session.close();
}
// 删除(测试对关联对象的影响)
@Test
public void testDelete() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// ---------------------------------------
// // 删除员工,对关联的部门没有影响
// Employee employee = (Employee) session.get(Employee.class, 1);
// session.delete(employee);
// // 删除部门,如果有关联的员工,则会:
// 1,inverse="false",这也是默认值,表示本方能维护关联关系(外键),这时会先把所有关联的员工都移除关系,再删除自己。
// 2,inverse="true",表示本方不能维护关联关系(外键),就会直接删除自己,这时会抛异常。
Dempartment department = (Dempartment) session.get(Dempartment.class, 2);
session.delete(department);
// ---------------------------------------
session.getTransaction().commit();
session.close();
}
}
二、多对多
public class Student {
private int id;
private String name;
private Set<Teacher> teacherSet = new HashSet<Teacher>();
}
public class Teacher {
private int id;
private String name;
private Set<Student> studentSet = new HashSet<Student>();
}
package pde.ams.manytomany;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
/**
* @author 作者 macx:
* @version 创建时间:2018年4月29日 下午1:40:06 类说明
*/
public class App {
private static SessionFactory sessionFactory = new Configuration()//
.configure()//
.addClass(Teacher.class)// 加载指定类对应的映射文件(以类名为前缀,后缀为.hbm.xml的同一个包下的文件)
.addClass(Student.class)// 加载指定类对应的映射文件(以类名为前缀,后缀为.hbm.xml的同一个包下的文件)
.buildSessionFactory();
@Test
public void saveUser() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// ---------------------------------------
// 创建对象
Teacher teacher1 = new Teacher();
teacher1.setName("赵老师");
Teacher teacher2 = new Teacher();
teacher2.setName("冯老师");
Student student1 = new Student();
student1.setName("张三");
Student student2 = new Student();
student2.setName("李四");
// 关联起来
teacher1.getStudentSet().add(student1);
teacher1.getStudentSet().add(student2);
teacher2.getStudentSet().add(student1);
teacher2.getStudentSet().add(student2);
student1.getTeacherSet().add(teacher1);
student1.getTeacherSet().add(teacher2);
student2.getTeacherSet().add(teacher1);
student2.getTeacherSet().add(teacher2);
// 保存
session.save(teacher1);
session.save(teacher2);
session.save(student1);
session.save(student2);
// ---------------------------------------
session.getTransaction().commit();
session.close();
}
@Test
public void getUser() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// ---------------------------------------
// 获取一个Student,并显示相关的Teacher信息
Student student = (Student) session.get(Student.class, 3);
System.out.println("学生的姓名:" + student.getName());
System.out.println("此学生的老师:" + student.getTeacherSet());
// ---------------------------------------
session.getTransaction().commit();
session.close();
}
// 移除关联关系
@Test
public void testRemoveRelation() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// ---------------------------------------
// 获取一个Student,并移除与所有老师的关联
Student student = (Student) session.get(Student.class, 5);
student.getTeacherSet().clear();
// Teacher teacher = (Teacher) session.get(Teacher.class, 5);
// teacher.getStudentSet().clear();
// ---------------------------------------
session.getTransaction().commit();
session.close();
}
// 删除(测试对关联对象的影响)
@Test
public void testDelete() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// ---------------------------------------
// 删除一个Student,如果有关联的老师,则:
// 如果inverse="false",表示可以维护关联关系,这时会先删除关系,再删除自己。
// 如果inverse="true",表示不可以维护关联关系,这时会直接删除自己,会有异常。
Student student = (Student) session.get(Student.class, 5);
session.delete(student);
// ---------------------------------------
session.getTransaction().commit();
session.close();
}
}
三、级联 cascade
1、概念
当hibernate持久化一个临时对象时,在默认情况下,他不会自动持久化所关联的其他临时对象,而是会抛出TransientObjectException.如果设定many-to-one元素的cascade属性为save-update的话,可实现自动持久化所关联的对象。
级联指的是当主控方执行操作时,关联对象(被动方)是否同步执行同一操作。
2、级联风格
每个 Hibernate session 的基本操作 — 包括 persist(), merge(), saveOrUpdate(), delete(),lock(), refresh(),evict(), replicate() — 都有对应的级联风格(cascade style)。这些级联风格(cascade style)风格分别命名为persist, merge, save-update,delete, lock, refresh, evict, replicate。
级联风格 | Session中的方法 |
persist | persist() |
merge | merge() |
save-update | save()、update()、saveOrUpdate() |
delete | delete() |
lock | lock() |
refresh | refresh() |
evict | evict() |
replicate | replicate() |
如果你希望一个操作被顺着关联关系级联传播,你必须在映射文件中指出这一点。
指定级联风格:
<one-to-one name="person" cascade="persist"/>
级联风格(cascadestyle)是可组合的:
<one-to-one name="person" cascade="persist,delete"/>
你可以使用 cascade="all" 来指定全部操作都顺着关联关系级联(cascaded)。默认值是cascade="none",即任何操作都不会被级联(cascaded)。
delete-orphan
A special cascade style, delete-orphan, applies only toone-to-many associations, and indicates that the delete() operation should beapplied to any child object that is removed from the association.
在对象–关系映射文件中, 用于映射持久化类之间关联关系的元素, 如<set>,<many-to-one> 和 <one-to-one> 都有一个 cascade属性。
public class Person {
private int id;
private String name;
private IdCard idCard;
}
public class IdCard {
private int id;
private String number;
private Person person;
}
---IdCard.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="pde.ams.onetoone">
<class name="IdCard" table="idCard">
<id name="id">
<generator class="native" />
</id>
<property name="number"></property>
<!-- person属性,表达IdCard与Person的一对一。 采用基于外键的一对一映射方式。 有外键方,就是多对一加上惟一性约束。 -->
<many-to-one name="person" class="Person" column="personId"
unique="true" cascade="save-update,delete"></many-to-one>
</class>
</hibernate-mapping>
---Person.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="pde.ams.onetoone">
<class name="Person" table="person">
<id name="id">
<generator class="native" />
</id>
<property name="name"></property>
<!-- idCard属性,表达的是Person与IdCard的一对一。 采用基于外键的一对一映射方式。 无外键方,使用one-to-one,property-ref写的是对方映射中表达此一对一的属性 -->
<one-to-one name="idCard" class="IdCard" property-ref="person" cascade="delete"></one-to-one>
</class>
</hibernate-mapping>
public class App {
private static SessionFactory sessionFactory = new Configuration()//
.configure()//
.addClass(Person.class)// 加载指定类对应的映射文件(以类名为前缀,后缀为.hbm.xml的同一个包下的文件)
.addClass(IdCard.class)// 加载指定类对应的映射文件(以类名为前缀,后缀为.hbm.xml的同一个包下的文件)
.buildSessionFactory();
@Test
public void saveUser() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// ---------------------------------------
Person p = new Person();
p.setName("张三");
IdCard idcard = new IdCard();
idcard.setNumber("12345678");
// 关联起来
// 使用基于外键的一对一时:Person是无外键方,不可以维护关联关系
// 使用基于外键的一对一时:IdCard是有外键方,可以维护关联关系
// 使用基于主键的一对一时:也是只有有外键方可以保存关联关系
p.setIdCard(idcard);
idcard.setPerson(p);
// 保存
// session.save(p);
session.save(idcard);
// ---------------------------------------
session.getTransaction().commit();
session.close();
}
@Test
public void getUser() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// ---------------------------------------
Person person = (Person) session.get(Person.class, 1);
IdCard id = (IdCard) session.get(IdCard.class, 1);
System.out.println(id);
System.out.println(id.getNumber());
System.out.println(id.getPerson().getName());
// ---------------------------------------
session.getTransaction().commit();
session.close();
}
// 移除关联关系
@Test
public void testRemoveRelation() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// ---------------------------------------
IdCard id = (IdCard) session.get(IdCard.class, 1);
id.setPerson(null);
session.save(id);
// ---------------------------------------
session.getTransaction().commit();
session.close();
}
// 删除(测试对关联对象的影响)
@Test
public void testDelete() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// ---------------------------------------
// IdCard id = (IdCard) session.get(IdCard.class, 1);
// session.delete(id);
Person p = (Person) session.get(Person.class, 2);
session.delete(p);
// ---------------------------------------
session.getTransaction().commit();
session.close();
}
五、继承关系映射
1、映射一(同一表中)
public class Article {
private Integer id;
private String title;
private String content;
}
public class Reply extends Article{
private int floor; // 楼层
}
public class Topic extends Article {
private int type; // 主题类型,比如精华帖、置顶帖等等
}
---Article.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="pde.ams.extend_1">
<!--
继承结构映射:整个继承结构一张表
discriminator-value属性:指定哪个值表示当前类型
-->
<class name="Article" table="article" discriminator-value="Article">
<id name="id">
<generator class="native"></generator>
</id>
<!-- 指定一个用于鉴别是什么类型的列 -->
<discriminator column="_class" type="string"></discriminator>
<property name="title"></property>
<property name="content" type="text" length="5000"></property>
<!-- 子类:Topic -->
<subclass name="Topic" discriminator-value="Topic">
<property name="type"></property>
</subclass>
<!-- 子类:Reply -->
<subclass name="Reply" discriminator-value="Reply">
<property name="floor"></property>
</subclass>
</class>
</hibernate-mapping>
2、映射二(三个不同表)
<?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="pde.ams.extend_2">
<!--
继承结构映射:每个类一张表,抽象也对应表。
每个类的映射中都要写表名。
子类映射中要指定一个外键列<key column="id"></key>
-->
<class name="Article" table="article">
<id name="id">
<generator class="native"></generator>
</id>
<property name="title"></property>
<property name="content" type="text" length="5000"></property>
<!-- 子类:Topic -->
<joined-subclass name="Topic" table="topic">
<key column="id"></key>
<property name="type"></property>
</joined-subclass>
<!-- 子类:Reply -->
<joined-subclass name="Reply" table="reply">
<key column="id"></key>
<property name="floor"></property>
</joined-subclass>
</class>
</hibernate-mapping>
3、映射三
<?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="pde.ams.extend_3">
<!--
继承结构映射:每个具体类一张表,抽象不对应表。
如果类是抽象的,就要写上abstract="true",这样就不会创建表了,也不需要table属性了。
这时不能使用identity主键生成策略,因为继承结构映射要求在整个继承结构中,所有数据的主键值不能重复。
-->
<class name="Article" table="article">
<id name="id">
<!-- increment策略,由Hibernate维护的主键增长 -->
<generator class="increment"></generator>
</id>
<property name="title"></property>
<property name="content" type="text" length="5000"></property>
<!-- 子类:Topic -->
<union-subclass name="Topic" table="topic">
<property name="type"></property>
</union-subclass>
<!-- 子类:Reply -->
<union-subclass name="Reply" table="reply">
<property name="floor"></property>
</union-subclass>
</class>
</hibernate-mapping>