Hibernate(七)

数据库中多表之间存在着三种关系,也即系统设计中的三种实体关系:多对多,一对多,一对一。

数据库中实体表之间的关系映射是采用外键来描述的,如下:

【一对多】

建表原则:在多的一方创建外键指向一的一方的主键

【多对多】

建表原则:创建一个中间表,中间表中至少两个字段作为外键分别指向多对多双方的主键

 【一对一】

建表原则有两种:

*唯一外间对应:假设一对一种的任意一方为多,在多的一方创建外键指向一的一方的主键,然后将外间设置为唯一

*逐渐对应:一方的主键作为另一方的主键

 

在Hibernate中采用java对象关系来描述数据表之间的关系,如下图

【一对一】:在本类中定义对方类型的对象。

【一对多】:图中是一个A对应多个B类类型的情况,需在A类以Set集合的方式引入B类型的对象,在B类中定义A类类型的属性A

【多对多】:在本类中定义对方类型的Set集合。

Hibernate的一对多关联映射:

创建实体:

一的一方的实体:

public class Customer {

	private Long cust_id;//客户编号(主键)
	private String cust_name;//客户名称(公司名称)
	private String cust_source;//客户信息来源
	private String cust_industry;//客户所属行业
	private String cust_level;//客户级别
	private String cust_phone;//固定电话
	private String cust_mobile;//移动电话
	
	//通过ORM方式表示:一个客户对应多个联系人
	//放置的多的一方的集合,Hibernate默认使用的是Set集合。
	private Set<LinkMan> linkMans  = new HashSet<LinkMan>();

    ......
}

多的一方的实体:

public class LinkMan {

	private Long lkm_id;//联系人编号(主键)
	private String lkm_name;//联系人姓名
	private String lkm_gender;//联系人性别
	private String lkm_phone;//联系人办公电话
	private String lkm_mobile;//联系人手机
	private String lkm_email;//联系人邮箱
	private String lkm_qq;//联系人qq
	private String lkm_position;//联系人职位
	private String lkm_memo;//联系人备注
	
	//通过ORM方式表示:一个联系人只能属于一个客户
	//放置的是一的一方的对象。
	private Customer customer;

    ......
}

创建映射:

多的一方的映射的创建:

<?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="com.ithou.hibernate.domain.LinkMan" table="cst_linkman">
		<!-- 建立类中的属性与表中的主键映射 -->
		<id name="lkm_id" column="lkm_id">
			<!-- 主键生成策略 -->
			<generator class="native"/>
		</id>
		<!-- 建立类中的普通属性与表中的字段对应 -->
		<property name="lkm_name" column="lkm_name"/>
		<property name="lkm_gender" column="lkm_gender"/>
		<property name="lkm_phone" column="lkm_phone"/>
		<property name="lkm_mobile" column="lkm_mobile"/>
		<property name="lkm_email" column="lkm_email"/>
		<property name="lkm_qq" column="lkm_qq"/>
		<property name="lkm_position" column="lkm_position"/>
		<property name="lkm_memo" column="lkm_memo"/>
		
		<!-- 配置多对一的关系:放置的是一的一方的对象 -->
		<!-- 
			many-to-one标签
				*name:一的一方的对象对象的属性名称
				*class:一的一方的类的全路径
				*column:在多的一方的表的外键的名称
		 -->
		<many-to-one name="customer" class="com.ithou.hibernate.domain.Customer" column="lkm_cust_id"></many-to-one>
	</class>

</hibernate-mapping>

一的一方的映射的创建:

<?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="com.ithou.hibernate.domain.Customer" table="cst_customer">
		<!-- 建立类中的属性与表中的主键映射 -->
		<id name="cust_id" column="cust_id">
			<!-- 主键生成策略 -->
			<generator class="native"/>
		</id>
		<!-- 建立类中的普通属性与表中的字段对应 -->
		<property name="cust_name" column="cust_name"/>
		<property name="cust_source" column="cust_source"/>
		<property name="cust_industry" column="cust_industry"/>
		<property name="cust_level" column="cust_level"/>
		<property name="cust_phone" column="cust_phone"/>
		<property name="cust_mobile" column="cust_mobile"/>
		<!-- 配置一对多的映射:放置的多的一方的集合 -->
		<!-- 
			set标签
				*name:多的一方的对象集合的属性名称
		 -->
		 <set name="linkMans">
		 	<!-- 
		 		key标签:
		 			*column:多的一方的外键的名称
		 	 -->
		 	<key column="lkm_cust_id"></key>
		 	<!-- 
		 		one-to-many标签:
		 		*class:多的一方的类的全路径
		 	 -->
		 	<one-to-many class="com.ithou.hibernate.domain.LinkMan"/>
		 </set>
	</class>

</hibernate-mapping>

编写测试类:

public class HibernateDemo1 {
	/**
	 * 保存2个客户和3个联系人
	 */
	@Test
	public void demo1() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction ts = session.beginTransaction();
		
		Customer customer1 = new Customer();
		customer1.setCust_name("zhangsan");
		Customer customer2 = new Customer();
		customer2.setCust_name("lisi");
		
		LinkMan linkMan1 = new LinkMan();
		linkMan1.setLkm_name("rufeng");
		LinkMan linkMan2 = new LinkMan();
		linkMan2.setLkm_name("zhangjian");
		LinkMan linkMan3 = new LinkMan();
		linkMan3.setLkm_name("libin");
		
		//设置关系
		customer1.getLinkMans().add(linkMan1);
		customer1.getLinkMans().add(linkMan2);
		customer2.getLinkMans().add(linkMan3);
		linkMan1.setCustomer(customer1);
		linkMan2.setCustomer(customer1);
		linkMan3.setCustomer(customer2);
		
		//保存数据
		session.save(customer1);
		session.save(customer2);
		session.save(linkMan1);
		session.save(linkMan2);
		session.save(linkMan3);
		
		ts.commit();
	}	
}

Hibernate一对多相关操作:

一对多关系只保存一边是否可以:不可以,报一个瞬时态对象异常:持久态对象关联了一个瞬时态对象

一对多的级联操作:

级联:操作一个对象的时候,是否会同时操作其关联的对象

级联是有方向性的:

*操作一的一方的时候,是否操作到多的一方

*操作多的一方的时候,是否操作到一的一方

级联保存或更新:

/**
 * 级联保存或更新
 * 保存客户级联联系人,操作的是客户对象,需要在Customer.hbm.xml中进行配置
 * <set name="linkMans" cascade="save-update">
 */
@Test
public void demo2() {
	Session session = HibernateUtils.getCurrentSession();
	Transaction ts = session.beginTransaction();
		
	Customer customer = new Customer();
	customer.setCust_name("zhaohong");
		
	LinkMan linkMan = new LinkMan();
	linkMan.setLkm_name("ruhua");
		
	//设置关系
	customer.getLinkMans().add(linkMan);
	linkMan.setCustomer(customer);
		
	//保存数据
	session.save(customer);

	ts.commit();
}

 

/**
 * 级联保存或更新
 * 保存联系人级联客户,操作的是联系人对象,需要在LinkMan.hbm.xml中进行配置
 * <many-to-one name="customer" cascade="save-update" class="com.ithou.hibernate.domain.Customer" column="lkm_cust_id"></many-to-one>
 */
@Test
public void demo3() {
	Session session = HibernateUtils.getCurrentSession();
	Transaction ts = session.beginTransaction();
	
	Customer customer = new Customer();
	customer.setCust_name("xiaolang");
		
	LinkMan linkMan = new LinkMan();
	linkMan.setLkm_name("xiaohong");
		
	//设置关系
	customer.getLinkMans().add(linkMan);
	linkMan.setCustomer(customer);
		
	//保存数据
	session.save(linkMan);

	ts.commit();
}

级联删除:

删除一边的时候,同时将另一方的数据也一并删除

/**
 * 级联删除
 * 删除客户级联联系人,删除的主体是客户,需要在Customer.hbm.xml中配置
 * <set name="linkMans" cascade="delete">
 */
@Test
public void demo4() {
	Session session = HibernateUtils.getCurrentSession();
	Transaction ts = session.beginTransaction();
		
	//没有设置级联删除,默认情况:修改了联系人的外键,删除客户
	/*Customer customer = session.get(Customer.class, 9l);
	session.delete(customer);*/
		
	Customer customer = session.get(Customer.class, 13l);
	session.delete(customer);
		
	ts.commit();
}

删除联系人级联客户(基本不用) 

/**
 * 级联删除:
 * 删除联系人级联客户,删除的主体是联系人,需要在LinkMan.hbm.xml中配置
 * <many-to-one name="customer" cascade="delete">
 */
@Test
public void demo5() {
	Session session = HibernateUtils.getCurrentSession();
	Transaction ts = session.beginTransaction();
		
	LinkMan linkMan = session.get(LinkMan.class, 2l);
	session.delete(linkMan);
		
	ts.commit();
}

一对多设置了双向关联产生多余的SQL语句:

解决多余的SQL语句:

*单向维护

*使一方放弃外键维护权:一的一方放弃。在set上配置inverse=“true”

区分cascade和inverse

cascade是操作关联对象的,inverse是控制一的一方是否控制外键的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值