一 表与表之间关系回顾
- 一对多
- 多对多
- 一对一
二 hibernate一对多操作
1 一对多映射配置
以客户联系人为列:客户是一,联系人是多
(1)创建两个实体类,一个客户,一个联系人
Customer.java
package entity;
import java.util.HashSet;
import java.util.Set;
public class Customer {
private Integer cid;
private String custName;
private String custLevel;
private String custSource;
private String custPhone;
private String custMobile;
// 在客户类里面表示多个联系人,一个客户有多个联系人
//在hibernate要求使用集合表示多的数据,使用set集合
private Set<LinkMan> setlinkMan = new HashSet<LinkMan>();
public Set<LinkMan> getSetlinkMan() {
return setlinkMan;
}
public void setSetlinkMan(Set<LinkMan> setlinkMan) {
this.setlinkMan = setlinkMan;
}
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
public String getCustLevel() {
return custLevel;
}
public void setCustLevel(String custLevel) {
this.custLevel = custLevel;
}
public String getCustSource() {
return custSource;
}
public void setCustSource(String custSource) {
this.custSource = custSource;
}
public String getCustPhone() {
return custPhone;
}
public void setCustPhone(String custPhone) {
this.custPhone = custPhone;
}
public String getCustMobile() {
return custMobile;
}
public void setCustMobile(String custMobile) {
this.custMobile = custMobile;
}
}
LinkMan.java
package entity;
public class LinkMan {
private Integer lkm_id;
private String lkm_name;
private String lkm_gender;
private String lkm_phone;
//在联系人实体类里面表示所属客户,一个联系人只能属于一个客户
private Customer customer;
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Integer getLkm_id() {
return lkm_id;
}
public void setLkm_id(Integer lkm_id) {
this.lkm_id = lkm_id;
}
public String getLkm_name() {
return lkm_name;
}
public void setLkm_name(String lkm_name) {
this.lkm_name = lkm_name;
}
public String getLkm_gender() {
return lkm_gender;
}
public void setLkm_gender(String lkm_gender) {
this.lkm_gender = lkm_gender;
}
public String getLkm_phone() {
return lkm_phone;
}
public void setLkm_phone(String lkm_phone) {
this.lkm_phone = lkm_phone;
}
}
(2)让实体类之间互相进行表示
-
在客户实体类里面有多个联系人
- 一个客户里面有多个联系人
-
在联系人实体类里面表示所属客户
- 一个联系人只能属于一个客户
(3)配置映射文件
- 一般一个实体类对应一个映射文件
Customer.hb,.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Customer" table="t_customer">
<id name="cid" column="cid">
<generator class="native"></generator>
</id>
<property name="custLevel" column="custLevel"></property>
<property name="custMobile" column="custMobile"></property>
<property name="custName" column="custName"></property>
<property name="custPhone" column="custPhone"></property>
<property name="custSource" column="custSource"></property>
<!--在客户映射文件中,表示所有联系人
使用set标签表示所有联系人
set标签里面有name属性,属性值写在客户实体类里面表示联系人的set集合
-->
<set name="setlinkMan">
<!--一对多建表,有外键
hibernate机制:双向维护外键,在一和多那一方配置外键
column属性值:外键名称-->
<key column="clid"></key>
<!--客户所有联系人,class里面写联系人实体类全路径-->
<one-to-many class="entity.LinkMan"></one-to-many>
</set>
</class>
</hibernate-mapping>
LinkMan.hbm.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.LinkMan" table="t_linkman">
<id name="lkm_id" column="lkm_id">
<generator class="native"></generator>
</id>
<property name="lkm_name" column="lkm_name"></property>
<property name="lkm_gender" column="lkm_gender"></property>
<property name="lkm_phone" column="lkm_phone"></property>
<!--表示联系人所属客户
name:因为联系人在实体类使用customer对象表示,写customer名称
class:customer全路径
column:外键名称
-->
<many-to-one name="customer" class="entity.Customer" column="clid"></many-to-one>
</class>
</hibernate-mapping>
- 把映射最基本配置完成
- 在映射文件中,配置一对多的关系
- 在客户映射文件中,表示所有联系人
<!--在客户映射文件中,表示所有联系人
使用set标签表示所有联系人
set标签里面有name属性,属性值写在客户实体类里面表示联系人的set集合
-->
<set name="setlinkMan">
<!--一对多建表,有外键
hibernate机制:双向维护外键,在一和多那一方配置外键
column属性值:外键名称-->
<key column="clid"></key>
<!--客户所有联系人,class里面写联系人实体类全路径-->
<one-to-many class="entity.LinkMan"></one-to-many>
</set>
- 在联系人映射文件中,表示所属客户
<!--表示联系人所属客户
name:因为联系人在实体类使用customer对象表示,写customer名称
class:customer全路径
column:外键名称
-->
<many-to-one name="customer" class="entity.Customer" column="clid"></many-to-one>
(4)创建核心配置文件
<mapping resource="Customer.hb,.xml"></mapping>
<mapping resource="LinkMan.hbm.xml"></mapping>
2 一对多级联操作
(1)级联操作
- 级联保存
添加一个客户,为这个客户添加多个联系人 - 级联删除
删除某一给我客户,这个客户里面的所有的联系人也删除
(2)一对多级联保存
目标:添加客户,为这个客户添加一个联系人
方法一:
import Utils.HibernateUtils;
import entity.Customer;
import entity.LinkMan;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
public class HibernateOnetoMany {
//演示一对多级联保存
@Test
public void testAddDemo1(){
Transaction tx = null;
try{
Session session = HibernateUtils.getSessionObject();
tx= session.beginTransaction();
//添加一个客户,为这个客户添加一个联系人
//1 创建客户和联系人对象
Customer customer = new Customer();
customer.setCustName("欧亚学院");
customer.setCustLevel("VIP");
customer.setCustSource("软工");
customer.setCustPhone("13692127465");
customer.setCustMobile("029864564");
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("杨某人");
linkMan.setLkm_gender("男");
linkMan.setLkm_phone("130****3381");
//2 在客户表示联系人,在联系人表示客户,建立客户对象和联系人对象关系
//2.1 把联系人对象放到客户对象的set集合里面
customer.getSetlinkMan().add(linkMan);
//2.2 把客户对象放到联系人里面去
linkMan.setCustomer(customer);
//3 保存到数据库
session.save(customer);
session.save(linkMan);
tx.commit();
}catch (Exception e){
e.printStackTrace();
tx.rollback();
}
}
}
方法二
一般根据客户添加联系人
第一步 在客户映射文件中添加配置
- 在客户映射文件中有set标签进行配置
第二步 创建客户和联系人对象,只需要把联系人放到客户里面就可以了,最终只需要保存客户就可以了
public void testAddDemo2(){
Transaction tx = null;
try{
Session session= HibernateUtils.getSessionObject();
tx = session.beginTransaction();
//1 创建客户和联系人对象
Customer customer = new Customer();
customer.setCustName("百度");
customer.setCustLevel("普通用户");
customer.setCustSource("网络");
customer.setCustPhone("13612227465");
customer.setCustMobile("021864564");
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("陈某人");
linkMan.setLkm_gender("女");
linkMan.setLkm_phone("130315245456");
//2 把联系人放到客户里面
customer.getSetlinkMan().add(linkMan);
//3 保存
session.save(customer);
tx.commit();
}catch (Exception e){
e.printStackTrace();
tx.rollback();
}
}
(3)级联删除
需求:删除某个客户,把客户里面所有的联系人删除
实现:
第一步 在客户映射文件set标签,进行配置
第二步 在代码中直接删除客户(根据id查询对象,调用session里面delete方法删除)
public void testDelDemo3(){
Transaction tx = null;
try{
Session session= HibernateUtils.getSessionObject();
tx = session.beginTransaction();
Customer customer= session.get(Customer.class,1);
session.delete(customer);
tx.commit();
}catch (Exception e){
e.printStackTrace();
tx.rollback();
}
}
执行过程:
- 根据id查询客户
- 根据外键id值查询联系人
- 把联系人的外键设置外null
- 删除联系人和客户
(4)一对多修改操作
需求:让陈某人联系人所属客户不属于百度,而是欧亚
@Test
public void testUpdateDemo4(){
Transaction tx = null;
try {
Session session = HibernateUtils.getSessionObject();
tx = session.beginTransaction();
//1 根据id查询陈某人,根据id查百度的客户
Customer eurasia= session.get(Customer.class,1);
LinkMan chen = session.get(LinkMan.class,2);
//2 设置持久态对象
//把联系人放到客户里面
eurasia.getSetlinkMan().add(chen);
//把客户放到联系人里面
chen.setCustomer(eurasia);
tx.commit();
}catch (Exception e){
e.printStackTrace();
tx.rollback();
}
}
(5)inverse属性
- 因为hibernate双向维护外键,在客户和联系人里面都需要维护外键,修改客户时候修改一次外键,修改联系人时候也修改一次外键,造成效率问题。
- 解决方式:让其中一方不维护外键(一对多里面,让其中一方放弃外键维护)
- 具体实现:在放弃关系维护映射文件中,进行配置,在set标签上使用inverse属性
说明:inverse属性默认值,false不放弃关系维护,true表示放弃关系维护