Hibernate关联关系的映射
2018-01-08 17:36
351 查看
1.1 Hibernate关联关系的映射:
1.1.1 实体之间的关系:
实体之间有三种关系:
* 一对多:
* 一个用户,生成多个订单,每一个订单只能属于一个用户.
* 建表原则:
* 在多的一方创建一个字段,作为外键,指向一的一方的主键.
* 多对多:
* 一个学生可以选择多门课程,一个课程可以被多个学生选择.
* 建表原则:
* 创建第三张表,中间表至少有两个字段,分别作为外键指向多对多双方主键.
* 一对一:(特殊.最少.)
* 一个公司只能有一个注册地址,一个注册地址,只能被一个公司使用.(否则将两个表建到一个
表.)
* 建表原则:
* 唯一外键:
* 一对一的双方,假设一方是多的关系.需要在多的一方创建一个字段,作为外键.指向一
的一方的主键.但是在外键添加一个unique.
* 主键对应:
* 一对一的双方,通过主键进行关联.
1.1.2 Hibernate中一对多的配置:(*****)
数据库准备:
create table customer2(
cid INT primary KEY auto_increment,
cname varchar(30)
)
insert into customer2 values(1,'hyf');
insert into customer2 values(2,'fy');
insert into customer2 values(3,'haha');
create table orders(
oid INT PRIMARY KEY auto_increment,
cid INT,
addr VARCHAR(30),
foreign key(cid) REFERENCES customer2(cid)
)
insert into orders values(null,1,'佛山');
insert into orders values(null,1,'广州');
insert into orders values(null,1,'四川');
insert into orders values(null,2,'佛山');
insert into orders values(null,2,'广州');
insert into orders values(null,2,'四川');
insert into orders values(null,3,'佛山');
insert into orders values(null,3,'广州');
insert into orders values(null,3,'四川');
第一步:
* 创建两个实体:
* 客户实体:
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;
}
@Override
public String toString() {
return "Customer [cid=" + cid + ", cname=" + cname + ",
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;
}
@Override
public String toString() {
return "Order [oid=" + oid + ", addr=" + addr + "]";
}
}
第二步:建立映射:
Customer.hbm.xml
<hibernate-mapping>
<class name="cn.itcast.hibernate3.demo2.Customer" table="customer2">
<!-- 配置唯一标识
-->
<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="cn.itcast.hibernate3.demo2.Order"/>
</set>
</class>
</hibernate-mapping>
Order.hbm.xml
<hibernate-mapping>
<class name="cn.itcast.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="cn.itcast.hibernate3.demo2.Customer"/>
</class>
</hibernate-mapping>
第三步:将映射放到核心配置文件中.
<mapping resource="。。。Customer.hbm.xml"/>
<mapping resource="。。。Order.hbm.xml"/>
发现:不能两个实体类的重写toString()方法中都带有对方
测试:
查询:
Customer customer = (Customer) session.get(Customer.class, 1);
System.out.println(customer);
System.out.println(customer.getOrders());
插入用户及其订单:
Customer customer = new Customer();
customer.setCname("阿黄");
Order order = new Order();
order.setAddr("广州");
customer.getOrders().add(order);
order.setCustomer(customer); --没有级联,还需要订单去关联用户
session.save(customer);--没有级联,用户和订单都要保存
session.save(order);
下面就不测试其他了,因为没级联极其的麻烦,下面将会进行级联后的测试
1.1.3 Hibernate中级联保存的效果:
级联:操作当前对象的时候,关联的对象如何处理.
cascade=”save-update”
级联方向性:
* 保存客户的时候,选择级联订单.
在Customer.hbm.xml的<set name="orders">标签添加上cascade="save-update"
* 保存订单的时候,选择级联客户.
在Order.hbm.xml的<many-to-one name="Customer">标签上添加上cascade="save-update"
级联保存测试:
保存用户及其订单
Customer custoemr= new Customer();
custoemr.setCname("何泳锋");
Order order = new Order();
order.setAddr("天下");
custoemr.getOrders().add(order); --订单不用再关联用户
session.save(custoemr); --只需要保存用户即可
级联更新测试:
将oid为1的订单的用户改为cid为8的用户:
Customer customer = (Customer) session.get(Customer.class, 8);
Order order = (Order) session.get(Order.class, 1);
//修改订单所属用户
order.setCustomer(customer); --一级缓存会自动发送SQL更新数据库对应表
//customer.getOrders().add(order); --因为修改后一级缓存的数据和一级缓存快照区的不一致
1.1.4 Hibernate中级联删除的效果:
cascade=”delete”
删除客户时可以删掉对应的订单(配置和上面的一样,变为cascade="save-update,delete")
级联删除测试:
Customer customer = (Customer) session.get(Customer.class, 3);
session.delete(customer); --一般都是建议先查询再删除,删除用户时,会发送删除对应订单SQL
tx.commit();
session.close();
1.1.5 Hibernate中的级联取值:
none :不使用级联
save-update :保存或更新的时候级联
delete :删除的时候级联
all :除了孤儿删除以外的所有级联.
delete-orphan :孤儿删除(孤子删除).
* 仅限于一对多.只有一对多时候,才有父子存在.认为一的一方是父亲,多的一方是子方.
* 当一个客户与某个订单解除了关系.将外键置为null.订单没有了所属客户,相当于一个孩子没有了父亲.将这种记录就删除了.
all-delete-orphan :包含了孤儿删除的所有的级联.
1.1.6 双向维护产生多余的SQL:
例如上面的级联删除,如果你信息看一下控制台的SQL的话,会发现会有两次删除订单的SQL,这就是双向维护产生多余的SQL,其实删除一次就够了。
那么我们应该配置inverse=”true”:在哪一端配置.那么哪一端放弃了外键的维护权.
* 一般情况下,一的一方去放弃.
这里的话就是在Customer的<set>标签中添加inverse="true",因为默认为false。
cascade:操作关联对象.
inverse:控制外键的维护.
1.1.7 Hibernate的多对多的配置:
数据库准备:
create table student(
sid int primary key auto_increment,
sname varchar(30)
)
create table course(
cid int PRIMARY key auto_increment,
cname VARCHAR(30)
)
create table stu_cou(
sno int,
cno int,
foreign KEY(sno) REFERENCES student(sid),
foreign key(cno) references course(cid)
)
insert into student values(null,'hyf');
insert into student values(null,'fy');
insert into course VALUES(null,'语文');
insert into course VALUES(null,'数学');
insert into course VALUES(null,'英语');
insert into stu_cou values(1,1);
insert into stu_cou values(1,2);
insert into stu_cou values(1,3);
insert into stu_cou values(2,1);
insert into stu_cou values(2,3);
第一步:创建实体类:
学生的实体:
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="cn.itcast.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="cn.itcast.hibernate3.demo3.Course" column="cno"/>
</set>
</class>
</hibernate-mapping>
Course.hbm.xml
<hibernate-mapping>
<class name="cn.itcast.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="cn.itcast.hibernate3.demo3.Student" column="sno"/>
</set>
</class>
</hibernate-mapping>
第三步:将映射文件加入到核心配置文件中:
查询测试:
List<Student> list= session.createQuery("from Student").list();
for(Student student : list) {
System.out.println(student);
}
1.1.8 Hibernate的多对多的保存:
两方都会改中间表的记录,多对多保存一定要有一方放弃外键的维护权
默认会出现错误,应该在主动方设置放弃外键的维护能力
*在Student.hbm.xml的set标签加上 inverse="true"。
级联保存测试:
新建student和course:
Student student = new Student();
student.setSname("哈哈");
Course course = new Course();
course.setCname("政治");
student.getCourses().add(course);
session.save(student);
级联修改测试:
Student student = (Student) session.get(Student.class, 3);
Course course = (Course) session.get(Course.class, 4);
student.getCourses().remove(course);
1.1.9 Hibernate的多对多的级联操作:
配置cascade
级联删除在多对多中是很少使用的
*例如删除学生的时候如果级联删除课程这是不太合理的做法
1.1.1 实体之间的关系:
实体之间有三种关系:
* 一对多:
* 一个用户,生成多个订单,每一个订单只能属于一个用户.
* 建表原则:
* 在多的一方创建一个字段,作为外键,指向一的一方的主键.
* 多对多:
* 一个学生可以选择多门课程,一个课程可以被多个学生选择.
* 建表原则:
* 创建第三张表,中间表至少有两个字段,分别作为外键指向多对多双方主键.
* 一对一:(特殊.最少.)
* 一个公司只能有一个注册地址,一个注册地址,只能被一个公司使用.(否则将两个表建到一个
表.)
* 建表原则:
* 唯一外键:
* 一对一的双方,假设一方是多的关系.需要在多的一方创建一个字段,作为外键.指向一
的一方的主键.但是在外键添加一个unique.
* 主键对应:
* 一对一的双方,通过主键进行关联.
1.1.2 Hibernate中一对多的配置:(*****)
数据库准备:
create table customer2(
cid INT primary KEY auto_increment,
cname varchar(30)
)
insert into customer2 values(1,'hyf');
insert into customer2 values(2,'fy');
insert into customer2 values(3,'haha');
create table orders(
oid INT PRIMARY KEY auto_increment,
cid INT,
addr VARCHAR(30),
foreign key(cid) REFERENCES customer2(cid)
)
insert into orders values(null,1,'佛山');
insert into orders values(null,1,'广州');
insert into orders values(null,1,'四川');
insert into orders values(null,2,'佛山');
insert into orders values(null,2,'广州');
insert into orders values(null,2,'四川');
insert into orders values(null,3,'佛山');
insert into orders values(null,3,'广州');
insert into orders values(null,3,'四川');
第一步:
* 创建两个实体:
* 客户实体:
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;
}
@Override
public String toString() {
return "Customer [cid=" + cid + ", cname=" + cname + ",
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;
}
@Override
public String toString() {
return "Order [oid=" + oid + ", addr=" + addr + "]";
}
}
第二步:建立映射:
Customer.hbm.xml
<hibernate-mapping>
<class name="cn.itcast.hibernate3.demo2.Customer" table="customer2">
<!-- 配置唯一标识
-->
<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="cn.itcast.hibernate3.demo2.Order"/>
</set>
</class>
</hibernate-mapping>
Order.hbm.xml
<hibernate-mapping>
<class name="cn.itcast.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="cn.itcast.hibernate3.demo2.Customer"/>
</class>
</hibernate-mapping>
第三步:将映射放到核心配置文件中.
<mapping resource="。。。Customer.hbm.xml"/>
<mapping resource="。。。Order.hbm.xml"/>
发现:不能两个实体类的重写toString()方法中都带有对方
测试:
查询:
Customer customer = (Customer) session.get(Customer.class, 1);
System.out.println(customer);
System.out.println(customer.getOrders());
插入用户及其订单:
Customer customer = new Customer();
customer.setCname("阿黄");
Order order = new Order();
order.setAddr("广州");
customer.getOrders().add(order);
order.setCustomer(customer); --没有级联,还需要订单去关联用户
session.save(customer);--没有级联,用户和订单都要保存
session.save(order);
下面就不测试其他了,因为没级联极其的麻烦,下面将会进行级联后的测试
1.1.3 Hibernate中级联保存的效果:
级联:操作当前对象的时候,关联的对象如何处理.
cascade=”save-update”
级联方向性:
* 保存客户的时候,选择级联订单.
在Customer.hbm.xml的<set name="orders">标签添加上cascade="save-update"
* 保存订单的时候,选择级联客户.
在Order.hbm.xml的<many-to-one name="Customer">标签上添加上cascade="save-update"
级联保存测试:
保存用户及其订单
Customer custoemr= new Customer();
custoemr.setCname("何泳锋");
Order order = new Order();
order.setAddr("天下");
custoemr.getOrders().add(order); --订单不用再关联用户
session.save(custoemr); --只需要保存用户即可
级联更新测试:
将oid为1的订单的用户改为cid为8的用户:
Customer customer = (Customer) session.get(Customer.class, 8);
Order order = (Order) session.get(Order.class, 1);
//修改订单所属用户
order.setCustomer(customer); --一级缓存会自动发送SQL更新数据库对应表
//customer.getOrders().add(order); --因为修改后一级缓存的数据和一级缓存快照区的不一致
1.1.4 Hibernate中级联删除的效果:
cascade=”delete”
删除客户时可以删掉对应的订单(配置和上面的一样,变为cascade="save-update,delete")
级联删除测试:
Customer customer = (Customer) session.get(Customer.class, 3);
session.delete(customer); --一般都是建议先查询再删除,删除用户时,会发送删除对应订单SQL
tx.commit();
session.close();
1.1.5 Hibernate中的级联取值:
none :不使用级联
save-update :保存或更新的时候级联
delete :删除的时候级联
all :除了孤儿删除以外的所有级联.
delete-orphan :孤儿删除(孤子删除).
* 仅限于一对多.只有一对多时候,才有父子存在.认为一的一方是父亲,多的一方是子方.
* 当一个客户与某个订单解除了关系.将外键置为null.订单没有了所属客户,相当于一个孩子没有了父亲.将这种记录就删除了.
all-delete-orphan :包含了孤儿删除的所有的级联.
1.1.6 双向维护产生多余的SQL:
例如上面的级联删除,如果你信息看一下控制台的SQL的话,会发现会有两次删除订单的SQL,这就是双向维护产生多余的SQL,其实删除一次就够了。
那么我们应该配置inverse=”true”:在哪一端配置.那么哪一端放弃了外键的维护权.
* 一般情况下,一的一方去放弃.
这里的话就是在Customer的<set>标签中添加inverse="true",因为默认为false。
cascade:操作关联对象.
inverse:控制外键的维护.
1.1.7 Hibernate的多对多的配置:
数据库准备:
create table student(
sid int primary key auto_increment,
sname varchar(30)
)
create table course(
cid int PRIMARY key auto_increment,
cname VARCHAR(30)
)
create table stu_cou(
sno int,
cno int,
foreign KEY(sno) REFERENCES student(sid),
foreign key(cno) references course(cid)
)
insert into student values(null,'hyf');
insert into student values(null,'fy');
insert into course VALUES(null,'语文');
insert into course VALUES(null,'数学');
insert into course VALUES(null,'英语');
insert into stu_cou values(1,1);
insert into stu_cou values(1,2);
insert into stu_cou values(1,3);
insert into stu_cou values(2,1);
insert into stu_cou values(2,3);
第一步:创建实体类:
学生的实体:
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="cn.itcast.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="cn.itcast.hibernate3.demo3.Course" column="cno"/>
</set>
</class>
</hibernate-mapping>
Course.hbm.xml
<hibernate-mapping>
<class name="cn.itcast.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="cn.itcast.hibernate3.demo3.Student" column="sno"/>
</set>
</class>
</hibernate-mapping>
第三步:将映射文件加入到核心配置文件中:
查询测试:
List<Student> list= session.createQuery("from Student").list();
for(Student student : list) {
System.out.println(student);
}
1.1.8 Hibernate的多对多的保存:
两方都会改中间表的记录,多对多保存一定要有一方放弃外键的维护权
默认会出现错误,应该在主动方设置放弃外键的维护能力
*在Student.hbm.xml的set标签加上 inverse="true"。
级联保存测试:
新建student和course:
Student student = new Student();
student.setSname("哈哈");
Course course = new Course();
course.setCname("政治");
student.getCourses().add(course);
session.save(student);
级联修改测试:
Student student = (Student) session.get(Student.class, 3);
Course course = (Course) session.get(Course.class, 4);
student.getCourses().remove(course);
1.1.9 Hibernate的多对多的级联操作:
配置cascade
级联删除在多对多中是很少使用的
*例如删除学生的时候如果级联删除课程这是不太合理的做法
相关文章推荐
- Hibernate 关联关系映射实例
- Hibernate 的关联关系映射
- Hibernate学习笔记3--映射关联关系
- hibernate 关联关系映射目录
- Hibernate 映射多对多关联关系
- Hibernate 关联关系映射 -双向关联
- 映射实体Bean的关联关系 -Hibernate Annotations
- Hibernate映射多对多关联关系
- Hibernate的关联关系注解映射(一对一、一对多、多对一、多对多、自连接) 标签: hibernateentity 2016-10-11 16:28 1635人阅读 评论(0) 收藏 举报 分类
- Hibernate框架基础——一对多关联关系映射
- Hibernate关联关系映射实例速查
- Hibernate_映射_关联关系_一对多多对一映射2、inverse属性
- Hibernate关联关系映射-----单向一对一映射配置
- Hibernate关联关系配置-----基于连接表的双向一对多/多对一映射配置
- 总结:Hibernate关联关系映射——七种映射的实现(更新中)
- hibernate 第七章 映射一对一 多对多关联关系
- Hibernate关联关系映射---1对1
- Hibernate(八):基于外键映射的1-1关联关系
- Hibernate 映射一对一关联关系
- Hibernate学习笔记----基于外键或主键映射的1-1关联关系