1.1 Hibernate关联关系的映射
1.1.1 实体之间的关系:
实体之间有三种关系:
* 一对多:
* 一个用户,生成多个订单,每一个订单只能属于一个用户.
* 建表原则:
* 在多的一方创建一个字段,作为外键,指向一的一方的主键.
* 多对多:
* 一个学生可以选择多门课程,一个课程可以被多个学生选择.
* 建表原则:
* 创建第三张表,中间表至少有两个字段,分别作为外键指向多对多双方主键.
* 一对一:(特殊.最少.)
* 一个公司只能有一个注册地址,一个注册地址,只能被一个公司使用.(否则将两个表建到一个表.)
* 建表原则:
* 唯一外键:
* 一对一的双方,假设一方是多的关系.需要在多的一方创建一个字段,作为外键.指向一的一方的主键.但是在外键添加一个unique.
* 主键对应:
* 一对一的双方,通过主键进行关联.
1.1.2 Hibernate中一对多的配置
第一步:
* 创建两个实体:
* 客户实体:
public class Customer {
private Integer cid;
private String cname;
// 一个客户有多个订单.
private Set<Order> orders = new HashSet<Order>();
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
}
* 订单实体:
public class Order {
private Integer oid;
private String addr;
// 订单属于某一个客户.放置一个客户的对象.
private Customer customer;
public Integer getOid() {
return oid;
}
public void setOid(Integer oid) {
this.oid = oid;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
第二步:建立映射:
Customer.hbm.xml
<hibernate-mapping>
<class name="com.sihai.hibernate3.demo2.Customer" table="customer">
<!-- 配置唯一标识 -->
<id name="cid" column="cid">
<generator class="native"/>
</id>
<!-- 配置普通属性 -->
<property name="cname" column="cname" length="20"/>
<!-- 建立映射 -->
<!-- 配置一个集合 <set>的name Customer对象中的关联对象的属性名称. -->
<set name="orders">
<!-- <key>标签中column:用来描述一对多多的一方的外键的名称. -->
<key column="cno"></key>
<!-- 配置一个<one-to-many>标签中class属性:订单的类的全路径 -->
<one-to-many class="com.sihai.hibernate3.demo2.Order"/>
</set>
</class>
</hibernate-mapping>
Order.hbm.xml
<hibernate-mapping>
<class name="com.sihai.hibernate3.demo2.Order" table="orders">
<!-- 配置唯一标识 -->
<id name="oid" column="oid">
<generator class="native"/>
</id>
<!-- 配置普通属性 -->
<property name="addr" column="addr" length="50"/>
<!-- 配置映射 -->
<!--
<many-to-one>标签
name :关联对象的属性的名称.
column:表中的外键名称.
class:关联对象类的全路径
-->
<many-to-one name="customer" column="cno" class="com.sihai.hibernate3.demo2.Customer"/>
</class>
</hibernate-mapping>
第三步:将映射放到核心配置文件中.
1.1.3 Hibernate中级联保存的效果:
级联:操作当前对象的时候,关联的对象如何处理.
cascade=”save-update”
级联方向性:
* 保存客户的时候,选择级联订单.
* 保存订单的时候,选择级联客户.
1.1.4 Hibernate中级联删除的效果:
cascade=”delete”
1.1.5 Hibernate中的级联取值:
none:不使用级联
save-update:保存或更新的时候级联
delete:删除的时候级联
all:除了孤儿删除以外的所有级联.
delete-orphan:孤儿删除(孤子删除).
* 仅限于一对多.只有一对多时候,才有父子存在.认为一的一方是父亲,多的一方是子方.
* 当一个客户与某个订单解除了关系.将外键置为null.订单没有了所属客户,相当于一个孩子没有了父亲.将这种记录就删除了.
all-delete-orphan:包含了孤儿删除的所有的级联.
1.1.6 双向维护产生多余的SQL:
配置inverse=”true”:在那一端配置.那么那一端放弃了外键的维护权.
* 一般情况下,一的一方去放弃.
cascade:操作关联对象.
inverse:控制外键的维护.
package com.sihai.hibernate3.demo2;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.sihai.utils.HibernateUtils;
/**
* 一对多的测试
* @author sihai
*
*/
public class HibernateTest2 {
@Test
// 区分cascade和inverse
// 在Customer.hbm.xml中的<set>上配置 cascade="save-update" inverse="true"
public void demo11(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer();
customer.setCname("张三");
Order order = new Order();
order.setAddr("西三旗");
customer.getOrders().add(order);
// 客户是否存到数据库:存
// 订单是否存到数据库:存 cascade="save-update".外键是null.
session.save(customer);
tx.commit();
session.close();
}
@Test
// 双向维护:自动更新数据库,产生多余的SQL.
// 双方都有外键的维护能力.必须让其中一方放弃外键的维护权.(一般情况下都是一的放弃.)
public void demo10(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Customer customer = (Customer) session.get(Customer.class, 1);
Order order = (Order) session.get(Order.class, 2);
customer.getOrders().add(order);
order.setCustomer(customer);
tx.commit();
session.close();
}
@Test
// 孤儿删除:
// 在Customer.hbm.xml中<set>上配置cascade="delete-orhpan"
public void demo9(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 让1号客户与1号订单解除关系:
Customer customer = (Customer) session.get(Customer.class, 1);
Order order = (Order) session.get(Order.class, 1);
customer.getOrders().remove(order);
tx.commit();
session.close();
}
@Test
// 级联删除:删除订单的时候,级联删除客户.
public void demo8(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Order order = (Order) session.get(Order.class, 1);
session.delete(order);
tx.commit();
session.close();
}
@Test
// 级联删除:删除客户的时候级联删除订单.
// 在Customer.hbm.xml的<set>标签上配置cascade="delete"
public void demo7(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 级联删除:先查询,在删除的方式.
Customer custoemr = (Customer) session.get(Customer.class, 1);
session.delete(custoemr);
tx.commit();
session.close();
}
@Test
// 删除一个客户:
// 默认的情况下,将外键置为null,删除数据记录.
public void demo6(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 删除的时候有两种:
// 先查询在删除的情况:
Customer customer = (Customer) session.get(Customer.class, 1);
session.delete(customer);
tx.commit();
session.close();
}
@Test
// 测试对象的导航关系:
public void demo5(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 定义一个客户:
Customer customer = new Customer();
customer.setCname("金刚");
// 定义三个订单
Order order1 = new Order();
order1.setAddr("西三旗");
Order order2 = new Order();
order2.setAddr("上地");
Order order3 = new Order();
order3.setAddr("五道口");
order1.setCustomer(customer);
customer.getOrders().add(order2);
customer.getOrders().add(order3);
// session.save(order1); // 共发送4条insert语句:
// session.save(customer);// 共发送3条insert语句:
session.save(order2);
tx.commit();
session.close();
}
@Test
// 保存订单级联客户.
// 在Order.hbm.xml中<many-to-one>配置cascade属性:级联保存
public void demo4(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 定义客户:
Customer customer = new Customer();
customer.setCname("郭浩");
// 定义订单:
Order order = new Order();
order.setAddr("西三旗中腾建华");
order.setCustomer(customer);
customer.getOrders().add(order);
// 保存的时候只保存一方:
session.save(order);
tx.commit();
session.close();
}
@Test
// 保存客户级联订单.
// <set>集合是客户的关联订单对象的集合.所以在<set>上配置一个属性:cascade="save-update"
public void demo3(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 定义客户:
Customer customer = new Customer();
customer.setCname("郭浩");
// 定义订单:
Order order = new Order();
order.setAddr("西三旗中腾建华");
order.setCustomer(customer);
customer.getOrders().add(order);
// 保存的时候只保存一方:
session.save(customer);
tx.commit();
session.close();
}
@Test
// 保存客户和订单的时候,是否可以只保存其中的一方?不行的报一个异常:一个持久态对象关联一个瞬时的对象.
public void demo2(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 定义客户:
Customer customer = new Customer();
customer.setCname("金刚");
// 定义订单:
Order order = new Order();
order.setAddr("五道口");
order.setCustomer(customer);
customer.getOrders().add(order);
// 保存的时候只保存一方:
session.save(customer);
tx.commit();
session.close();
}
@Test
// 向客户表插入一个客户,在订单表中插入两个订单.
public void demo1(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 定义一个客户:
Customer customer = new Customer();
customer.setCname("郭浩");
// 定义两个订单:
Order order1 = new Order();
order1.setAddr("西三旗中腾");
Order order2 = new Order();
order2.setAddr("西三旗金燕龙");
// 建立关系:
order1.setCustomer(customer);
order2.setCustomer(customer);
customer.getOrders().add(order1);
customer.getOrders().add(order2);
session.save(customer);
session.save(order1);
session.save(order2);
tx.commit();
session.close();
}
}
1.1.7 Hibernate的多对多的配置:
第一步:创建实体类:
学生的实体:
public class Student {
private Integer sid;
private String sname;
// 一个学生选择多门课程:
private Set<Course> courses = new HashSet<Course>();
public Integer getSid() {
return sid;
}
public void setSid(Integer sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Set<Course> getCourses() {
return courses;
}
public void setCourses(Set<Course> courses) {
this.courses = courses;
}
}
课程的实体:
public class Course {
private Integer cid;
private String cname;
// 一个课程被多个学生选择:
private Set<Student> students = new HashSet<Student>();
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}
第二步建立映射:
Student.hbm.xml
<hibernate-mapping>
<class name="com.sihai.hibernate3.demo3.Student" table="student">
<!-- 配置唯一标识 -->
<id name="sid" column="sid">
<generator class="native"/>
</id>
<!-- 配置普通属性 -->
<property name="sname" column="sname" length="20"/>
<!-- 配置关联映射 -->
<!-- <set>标签 name:对应学生中的课程集合的名称 table:中间表名称. -->
<set name="courses" table="stu_cour">
<!-- <key>中column写 当前类在中间表的外键.-->
<key column="sno"></key>
<!-- <many-to-many>中class:另一方类的全路径. column:另一方在中间表中外键名称-->
<many-to-many class="com.sihai.hibernate3.demo3.Course" column="cno"/>
</set>
</class>
</hibernate-mapping>
Course.hbm.xml
<hibernate-mapping>
<class name="com.sihai.hibernate3.demo3.Course" table="course">
<!-- 配置唯一标识 -->
<id name="cid" column="cid">
<generator class="native"/>
</id>
<!-- 配置普通属性 -->
<property name="cname" column="cname" length="20"/>
<!-- 配置与学生关联映射 -->
<!-- <set>中name:对应当前类中的学生的集合的名称 table:中间表的名称-->
<set name="students" table="stu_cour">
<!-- <key>中column:当前类在中间表中外键 -->
<key column="cno"></key>
<!-- <many-to-many>中class:另一方的类全路径. column:另一方在中间表中外键名称 -->
<many-to-many class="com.sihai.hibernate3.demo3.Student" column="sno"/>
</set>
</class>
</hibernate-mapping>
第三步:将映射文件加入到核心配置文件中:
测试:
package com.sihai.hibernate3.demo3;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.sihai.utils.HibernateUtils;
/**
* 多对多的测试类:
*
* @author sihai
*
*/
public class HibernateTest3 {
@Test
// 多对多的学生退选.
public void demo4(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 查询一号学生
Student student = (Student) session.get(Student.class, 1);
Course course = (Course) session.get(Course.class, 2);
student.getCourses().remove(course);
tx.commit();
session.close();
}
@Test
// 级联删除:在多对多中很少使用.
// 删除:删除学生同时删除学生关联选课
public void demo3(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Student student = (Student) session.get(Student.class, 3);
session.delete(student);
tx.commit();
session.close();
}
@Test
// 级联操作:级联保存:保存学生关联课程
// 在Student.hbm.xml中配置<set>上 cascade="save-update"
public void demo2() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 创建学生:
Student student1 = new Student();
student1.setSname("王五");
// 创建课程:
Course course1 = new Course();
course1.setCname("PHP语言");
student1.getCourses().add(course1);
course1.getStudents().add(student1);
session.save(student1);
tx.commit();
session.close();
}
@Test
// 保存学生和课程.为学生选择一些课程:
public void demo1() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 创建学生:
Student student1 = new Student();
student1.setSname("张三");
Student student2 = new Student();
student2.setSname("李四");
// 创建课程:
Course course1 = new Course();
course1.setCname("Java语言");
Course course2 = new Course();
course2.setCname("Android语言");
// 张三选1号和2号课
student1.getCourses().add(course1);
student1.getCourses().add(course2);
course1.getStudents().add(student1);
course2.getStudents().add(student1);
student2.getCourses().add(course1);
course1.getStudents().add(student2);
// 执行保存:
session.save(student1);
session.save(student2);
session.save(course1);
session.save(course2);
tx.commit();
session.close();
}
}