Java网课基础笔记(42)19-08-22

本文详细介绍了ORM框架Hibernate中一对一、一对多和多对多的关联关系映射方法,包括建表原则、JavaBean编写、映射配置、级联操作及外键维护等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

 

第一章 完成CRM到联系人的保存操作

1.1. 需求分析

1.2. 技术分析之Hibernate的关联关系映射之一对多映射(重点)

1.2.1 JavaWeb中一对多的设计及其建表原则

1.2.2.  SQL的建表

1.2.3. 编写客户和联系人的JavaBean程序(注意一对多的编写规则)

1.2.4. 编写客户和联系人的映射配置文件

1.2.5. 配置文件和具体说明

1.2.6. 进行双向关联进行数据的保存

1.3.  技术分析之及联保存

1.3.1. 及联保存示例

1.4. 技术分析之及联删除

1.4.1. 及联删除示例1

1.4.2. 及联删除示例2

1.5. 技术分析之及联的取值(cascade的取值)和孤儿删除(在一对多的环境下才有)

1.6. 技术分析之让某一方放弃外键的维护,为多对多做准备

1.6.1. inverse示例

第二章 Hibernate的关联关系映射之多对多映射

2.1. 技术分析之多对多的建表原则

2.2. 技术分析之多对多JavaBean的编写

2.3. 用户和角色的映射配置文件如下

2.4. hibernate.cfg.xml配置文件引入映射文件

2.5. 技术分析之多对多的及联保存——双向

2.6. 技术分析之多对多的及联保存——单向

2.7. 及联删除(在多对多中是很少使用的)


第一章 完成CRM到联系人的保存操作

1.1. 需求分析

因为客户和联系人是一对多的联系,在有客户的情况下,完成联系人的添加保存操作

1.2. 技术分析之Hibernate的关联关系映射之一对多映射(重点)

1.2.1 JavaWeb中一对多的设计及其建表原则

1.2.2.  SQL的建表

CREATE TABLE `hibernate_two`.`cst_linkman` (
  `lkm_id` BIGINT(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)',
  `lkm_name` VARCHAR(16) NULL COMMENT '联系人姓名',
  `lkm_cust_id` BIGINT(32) NULL COMMENT '客户id',
  `lkm_gender` CHAR(1) NULL COMMENT '联系人性别',
  `lkm_phone` VARCHAR(16) NULL COMMENT '联系人办公电话',
  `lkm_mobile` VARCHAR(16) NULL COMMENT '联系人人手机',
  `lkm_email` VARCHAR(64) NULL COMMENT '联系人邮箱',
  `lkm_qq` VARCHAR(16) NULL COMMENT '联系人qq',
  `lkm_position` VARCHAR(16) NULL COMMENT '联系人职位',
  `lkm_memo` VARCHAR(512) NULL COMMENT '联系人备注',
  PRIMARY KEY (`lkm_id`),
  INDEX `FK_cst_linkman_lkm_cust_id_idx` (`lkm_cust_id` ASC) VISIBLE,
  CONSTRAINT `FK_cst_linkman_lkm_cust_id`
    FOREIGN KEY (`lkm_cust_id`)
    REFERENCES `hibernate_two`.`cst_customer` (`cust_id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION);

1.2.3. 编写客户和联系人的JavaBean程序(注意一对多的编写规则)

客户的JavaBean-Customer.java

package com.feng.domain;

import java.util.HashSet;
import java.util.Set;



public class Customer {
private Long cust_id;
private String cust_name;
private Long cust_user_id;
private Long cust_create_id;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_linkman;
private String cust_phone;
private String cust_mobile;
//使用set集合表示多个联系人
private Set<LinkMan> linkMans=new HashSet<LinkMan>();

public Set<LinkMan> getLinkMans() {
	return linkMans;
}
public void setLinkMans(Set<LinkMan> linkMans) {
	this.linkMans = linkMans;
}
public Long getCust_id() {
	return cust_id;
}
public void setCust_id(Long cust_id) {
	this.cust_id = cust_id;
}
public String getCust_name() {
	return cust_name;
}
public void setCust_name(String cust_name) {
	this.cust_name = cust_name;
}
public Long getCust_user_id() {
	return cust_user_id;
}
public void setCust_user_id(Long cust_user_id) {
	this.cust_user_id = cust_user_id;
}
public Long getCust_create_id() {
	return cust_create_id;
}
public void setCust_create_id(Long cust_create_id) {
	this.cust_create_id = cust_create_id;
}
public String getCust_source() {
	return cust_source;
}
public void setCust_source(String cust_source) {
	this.cust_source = cust_source;
}
public String getCust_industry() {
	return cust_industry;
}
public void setCust_industry(String cust_industry) {
	this.cust_industry = cust_industry;
}
public String getCust_level() {
	return cust_level;
}
public void setCust_level(String cust_level) {
	this.cust_level = cust_level;
}
public String getCust_linkman() {
	return cust_linkman;
}
public void setCust_linkman(String cust_linkman) {
	this.cust_linkman = cust_linkman;
}
public String getCust_phone() {
	return cust_phone;
}
public void setCust_phone(String cust_phone) {
	this.cust_phone = cust_phone;
}
public String getCust_mobile() {
	return cust_mobile;
}
public void setCust_mobile(String cust_mobile) {
	this.cust_mobile = cust_mobile;
}
@Override
public String toString() {
	return "Customer [cust_id=" + cust_id + ", cust_name=" + cust_name + ", cust_user_id=" + cust_user_id
			+ ", cust_create_id=" + cust_create_id + ", cust_source=" + cust_source + ", cust_industry=" + cust_industry
			+ ", cust_level=" + cust_level + ", cust_linkman=" + cust_linkman + ", cust_phone=" + cust_phone
			+ ", cust_mobile=" + cust_mobile + "]";
}

}

联系人JavaBean-LinkMan.java

package com.feng.domain;

public class LinkMan {
	private Integer lkm_id;
	private String lkm_name;
	// 客户lkm_cust_id是外键,不用写
	private String lkm_gender;
	private String lkm_phone;
	private String lkm_mobile;
	private String lkm_email;
	private String lkm_qq;
	private String lkm_position;
	private String lkm_memo;
	// 客户类
	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;
	}

	public String getLkm_mobile() {
		return lkm_mobile;
	}

	public void setLkm_mobile(String lkm_mobile) {
		this.lkm_mobile = lkm_mobile;
	}

	public String getLkm_email() {
		return lkm_email;
	}

	public void setLkm_email(String lkm_email) {
		this.lkm_email = lkm_email;
	}

	public String getLkm_qq() {
		return lkm_qq;
	}

	public void setLkm_qq(String lkm_qq) {
		this.lkm_qq = lkm_qq;
	}

	public String getLkm_position() {
		return lkm_position;
	}

	public void setLkm_position(String lkm_position) {
		this.lkm_position = lkm_position;
	}

	public String getLkm_memo() {
		return lkm_memo;
	}

	public void setLkm_memo(String lkm_memo) {
		this.lkm_memo = lkm_memo;
	}

	@Override
	public String toString() {
		return "LinkMan [lkm_id=" + lkm_id + ", lkm_name=" + lkm_name + ", lkm_gender=" + lkm_gender + ", lkm_phone="
				+ lkm_phone + ", lkm_mobile=" + lkm_mobile + ", lkm_email=" + lkm_email + ", lkm_qq=" + lkm_qq
				+ ", lkm_position=" + lkm_position + ", lkm_memo=" + lkm_memo + "]";
	}

}

1.2.4. 编写客户和联系人的映射配置文件

客户映射文件Customer.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>
<!-- javabean与表之间的对应关系 -->
<class name="com.feng.domain.Customer" table="cst_customer">
<!-- 主键对应 -->
<id name="cust_id" column="cust_id">
<!-- 主键策略(与自增长相关) -->
<generator class="native"></generator>
</id>
<!-- 其他字段 -->
<property name="cust_name" column="cust_name"></property>
<property name="cust_user_id" column="cust_user_id"></property>
<property name="cust_create_id" column="cust_create_id"></property>
<property name="cust_source" column="cust_source"></property>
<property name="cust_industry" column="cust_industry"></property>
<property name="cust_level" column="cust_level"></property>
<property name="cust_linkman" column="cust_linkman"></property>
<property name="cust_phone" column="cust_phone"></property>
<property name="cust_mobile" column="cust_mobile"></property>
<!-- 设置与多方的关系 -->
<!-- name:javabean中set集合的名称
	key:column:外键名称
	one-to-many class:set集合中类的全路径 -->
<set name="linkMans">
	<key column="lkm_cust_id"></key>
	<!-- 一对多关系 -->
	<one-to-many class="com.feng.domain.LinkMan"/>
</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>
	<!-- javabean与表之间的对应关系 -->
	<class name="com.feng.domain.LinkMan" table="cst_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>
		<property name="lkm_mobile" column="lkm_mobile"></property>
		<property name="lkm_email" column="lkm_email"></property>
		<property name="lkm_qq" column="lkm_qq"></property>
		<property name="lkm_position" column="lkm_position"></property>
		<property name="lkm_memo" column="lkm_memo"></property>
		<!-- 设置多对一关系 -->
		<!-- name:javabean的属性名称 class:属性的类的全路径 column:外键名称 -->
		<many-to-one name="customer"
			class="com/feng/domain/Customer.java" column="lkm_cust_id"></many-to-one>
	</class>
</hibernate-mapping>

1.2.5. 配置文件和具体说明

  • 一方
<!-- name:javabean中set集合的名称
	key:column:外键名称
	one-to-many class:set集合中类的全路径 -->
<set name="linkMans">
	<key column="lkm_cust_id"></key>
	<!-- 一对多关系 -->
	<one-to-many class="com.feng.domain.LinkMan"/>
</set>
  • 多方
<!-- 设置多对一关系 -->
		<!-- name:javabean的属性名称 class:属性的类的全路径 column:外键名称 -->
		<many-to-one name="customer"
			class="com/feng/domain/Customer.java" column="lkm_cust_id"></many-to-one>

1.2.6. 进行双向关联进行数据的保存

在测试类增加测试方法

// 双向关联
	@Test
	public void test01() {
		Session session = HibernateUtil.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		// 新建一个客户
		Customer customer = new Customer();
		customer.setCust_name("张艺兴");
		// 新建2两个联系人
		LinkMan man1 = new LinkMan();
		man1.setLkm_name("张艺兴的粉丝1");
		LinkMan man2 = new LinkMan();
		man2.setLkm_name("张艺兴的粉丝2");
		// 双向关联(一方get,多方set)
		customer.getLinkMans().add(man1);
		customer.getLinkMans().add(man2);
		man1.setCustomer(customer);
		man2.setCustomer(customer);
		// 开始保存
		session.save(customer);
		session.save(man1);
		session.save(man2);
		// 提交
		transaction.commit();
		//不需要手动关闭session,不然会报错,提交完成后自动关闭session
		//session.close();

	}

运行结果

1.3.  技术分析之及联保存

1.测试:如果现在代码只插入其中的一方数据

  • 如果只保存其中的一方数据,则程序报错
  • 如果想完成只保存一方的数据,并且把相关联的数据都保存到数据库中,那么需要配置及联
  • 及联保存是方向性

2. 级联保存效果

  • 级联保存:保存一方同时可以把关联的对象也保存到数据库中!!
  • 使用cascade="save-update"

1.3.1. 及联保存示例

1.在测试类增加测试方法

// 单向关联
		@Test
		public void test02() {
			Session session = HibernateUtil.getCurrentSession();
			Transaction transaction = session.beginTransaction();
			// 新建一个客户
			Customer customer = new Customer();
			customer.setCust_name("张艺兴1");
			// 新建2两个联系人
			LinkMan man1 = new LinkMan();
			man1.setLkm_name("张艺兴1的粉丝1");
			LinkMan man2 = new LinkMan();
			man2.setLkm_name("张艺兴1的粉丝2");
			// 单向关联
			//客户关联联系人
			customer.getLinkMans().add(man1);
			customer.getLinkMans().add(man2);
			// 开始保存
			session.save(customer);
			// 提交
			transaction.commit();
			//不需要手动关闭session,不然会报错,提交完成后自动关闭session
			//session.close();

		}

运行结果(报错 ;原因--在hibernate代码中,在session.flush前,不允许持久态对象关联瞬时态对象,持久态对象只能关联持久态对象)

解决:采用及联,cascade:cascade=“save-update”

它的作用:

  • 可以使持久态对象“关联”瞬时态对象,自动会隐式执行save操作,变为持久态
  • 可以使持久态对象“关联”脱管态,自动会隐式执行update操作,变为持久态

如果通过操作customer来及联保存linkman,需要在Customer.hbm.xml(谁是持久的)配置及联

2.修改Customer.hbm.xml

<!-- 配置及联保存 cascade="save-update" 让瞬时态对象变成持久态 -->
<set name="linkMans" cascade="save-update">
	<!-- 外键-->
	<key column="lkm_cust_id"></key>
	<!-- 一对多关系 -->
	<one-to-many class="com.feng.domain.LinkMan"/>
</set>

3.测试,再次执行上面的测试方法

使用及联之后,hibernate会对瞬时态的这个对象,会自动执行save操作

问题:如果要保存联系人,及联保存客户呢?

修改LinkMan.hbm.xml

<!-- 配置及联保存 cascade:save-update 把瞬时态的客户变成持久态 -->
		<many-to-one name="customer" class="com.feng.domain.Customer" column="lkm_cust_id" cascade="save-update"></many-to-one>

在测试类增加测试方法

//单向关联  保存联系人
		@Test
		public void test03() {
			Session session = HibernateUtil.getCurrentSession();
			Transaction transaction = session.beginTransaction();
			// 新建一个客户
			Customer customer = new Customer();
			customer.setCust_name("张艺兴");
			// 新建2两个联系人
			LinkMan man1 = new LinkMan();
			man1.setLkm_name("张艺兴的粉丝1");
			LinkMan man2 = new LinkMan();
			man2.setLkm_name("张艺兴的粉丝2");
			// 单向关联(联系人关联客户
			man1.setCustomer(customer);
			man2.setCustomer(customer);
			// 开始保存
			session.save(man1);
			session.save(man2);
			// 提交
			transaction.commit();
			//不需要手动关闭session,不然会报错,提交完成后自动关闭session
			//session.close();
		}

测试结果(注意,SQL语句变少了)

及联保存配置在多方,减少sqlyuj,提高效率

1.4. 技术分析之及联删除

1. 先来给大家在数据库中演示含有外键的删除客户功能,那么SQL语句是会报出错误的

  • 例如:delete from cst_customer where cust_id = 1;

2. 如果使用Hibernate框架直接删除客户的时候,测试发现是可以删除的
3. 上述的删除是普通的删除,那么也可以使用级联删除,注意:级联删除也是有方向性的!!

  • <many-to-one cascade="delete" />

1.4.1. 及联删除示例1

1.修改Customer.hbm.xml

<!-- 配置及联删除 cascade="delete"-->
<set name="linkMans" cascade="delete">
	<!-- 外键-->
	<key column="lkm_cust_id"></key>
	<!-- 一对多关系 -->
	<one-to-many class="com.feng.domain.LinkMan"/>
</set>

还原LinkMan.hbm.xml配置

<many-to-one name="customer" class="com.feng.domain.Customer" column="lkm_cust_id" ></many-to-one>

2.在测试类中增加测试方法

//及联删除 删除客户
		@Test
		public void testDelete() {
			Session session = HibernateUtil.getCurrentSession();
			Transaction transaction = session.beginTransaction();
			Customer customer=session.get(Customer.class, 5L);
			session.delete(customer);
			transaction.commit();
		}

测试结果

1.4.2. 及联删除示例2

1.修改LinkMan.hbn.xml

<!-- 配置及联删除 -->
		<many-to-one name="customer" class="com.feng.domain.Customer" column="lkm_cust_id" cascade="delete"></many-to-one>

修改Customer.hbm.xml

<set name="linkMans" >
	<!-- 外键-->
	<key column="lkm_cust_id"></key>
	<!-- 一对多关系 -->
	<one-to-many class="com.feng.domain.LinkMan"/>
</set>

2.在测试类增加增长方法

// 及联删除 删除联系人
	@Test
	public void testDeleteLkm() {
		Session session = HibernateUtil.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		LinkMan linkMan = session.get(LinkMan.class, 6);
		session.delete(linkMan);
		transaction.commit();
	}

测试结果

3.测试发现剩下一条联系人数据没有关联到客户,这条数据已无用,说明这种方式不合理,即及联删除不适用于多方

1.5. 技术分析之及联的取值(cascade的取值)和孤儿删除(在一对多的环境下才有)

1. 需要大家掌握的取值如下

  • none ——不使用级联
  •  save-update  ——级联保存或更新
  •  delete  —— 级联删除
  • delete-orphan ——孤儿删除.(注意:只能应用在一对多关系)
  • all —— 除了delete-orphan的所有情况.(包含save-update delete)
  • all-delete-orphan  ——包含了delete-orphan的所有情况.(包含save-update delete delete-orphan)

2. 孤儿删除(孤子删除),只有在一对多的环境下才有孤儿删除

  •  在一对多的关系中,可以将一的一方认为是父方.将多的一方认为是子方.孤儿删除:在解除了父子关系的时候.将子方记录就直接删除。
  • <many-to-one cascade="delete-orphan" />

1.5.1. 孤儿删除示例

1.修改LinkMan.hbm.xml

<many-to-one name="customer" class="com.feng.domain.Customer" column="lkm_cust_id"></many-to-one>

修改Customer.hbm.xml

<set name="linkMans" cascade="delete-orphan" >
	<!-- 外键-->
	<key column="lkm_cust_id"></key>
	<!-- 一对多关系 -->
	<one-to-many class="com.feng.domain.LinkMan"/>
</set>

2.在测试类中增加测试方法

// 孤儿删除
	@Test
	public void testDeleteOrphan() {
		Session session = HibernateUtil.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		// 获取一个客户
		Customer customer = session.get(Customer.class, 2L);
		// 获取这个客户的2号联系人
		LinkMan man2 = session.get(LinkMan.class, 4);
		// 解除关系
		// 由快照机制实现
		customer.getLinkMans().remove(man2);
		transaction.commit();
	}

测试结果

一般在业务开发中,不要两端都配置及联,多方尽量不要配置及联,尽量在一方配置及联

1.6. 技术分析之让某一方放弃外键的维护,为多对多做准备

1. 先测试双方都维护外键的时候,会产生多余的SQL语句。

  •  想修改客户和联系人的关系,进行双向关联,双方都会维护外键,会产生多余的SQL语句。
  •  产生的原因:session的一级缓存中的快照机制,会让双方都更新数据库,产生了多余的SQL语句。

2. 如果不想产生多余的SQL语句,那么需要一方来放弃外键的维护!

  • 在<set>标签上配置一个inverse=”true”.true:放弃.false:不放弃.默认值是false
  •  <inverse="true">

1.6.1. inverse示例

问题:多余sql的问题

将没有关系的一个客户和联系人建立关系(双方)

直接在数据库联系人表增加联系人

INSERT INTO `hibernate_two`.`cst_linkman` (`lkm_name`) VALUES ('刘亦菲');

在客户表里增加客户

INSERT INTO `hibernate_two`.`cst_customer` (`cust_name`) VALUES ('胡歌');

修改Customer.hbm.xml

<set name="linkMans" inverse="true" >
	<!-- 外键-->
	<key column="lkm_cust_id"></key>
	<!-- 一对多关系 -->
	<one-to-many class="com.feng.domain.LinkMan"/>
</set>

在测试类增加测试方法

@Test
	public void test04() {
		Session session = HibernateUtil.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		// 获取一个客户
		Customer customer = session.get(Customer.class, 6L);
		LinkMan man=session.get(LinkMan.class, 9);
		//双向关联
		customer.getLinkMans().add(man);
		man.setCustomer(customer);
		session.save(customer);
		session.save(man);
		transaction.commit();
	}

测试结果(只有多方进行维护)

1.7. 技术分析之cascade和inverse的区别

  1.  cascade用来级联操作(保存、修改和删除)——在一方设置
  2.  inverse用来维护外键的 ——在一方设置

第二章 Hibernate的关联关系映射之多对多映射

2.1. 技术分析之多对多的建表原则

建立一个中间表

新建用户表

CREATE TABLE `hibernate_two`.`sys_user` (
  `user_id` BIGINT(32) NOT NULL AUTO_INCREMENT COMMENT '用户id',
  `user_code` VARCHAR(32) NULL COMMENT '用户账户',
  `user_name` VARCHAR(64) NULL COMMENT '用户名称',
  `user_password` VARCHAR(32) NULL COMMENT '用户密码',
  `user_state` CHAR(1) NULL COMMENT '1:正常;0:暂停',
  PRIMARY KEY (`user_id`));

 

新建角色表

CREATE TABLE `hibernate_two`.`sys_role` (
  `role_id` BIGINT(32) NOT NULL AUTO_INCREMENT,
  `role_name` VARCHAR(32) NULL COMMENT '角色名称',
  `role_memo` VARCHAR(128) NULL COMMENT '备注',
  PRIMARY KEY (`role_id`));

2.2. 技术分析之多对多JavaBean的编写

编写User.java

package com.web.domain;

import java.util.HashSet;
import java.util.Set;

public class User {
	private Long user_id;
	private String user_code;
	private String user_name;
	private String user_password;
	private String user_state;
	//用set集合存多个角色
	private Set<Role> roles=new HashSet<Role>();
	public Set<Role> getRoles() {
		return roles;
	}
	public void setRoles(Set<Role> roles) {
		this.roles = roles;
	}
	public Long getUser_id() {
		return user_id;
	}
	public void setUser_id(Long user_id) {
		this.user_id = user_id;
	}
	public String getUser_code() {
		return user_code;
	}
	public void setUser_code(String user_code) {
		this.user_code = user_code;
	}
	public String getUser_name() {
		return user_name;
	}
	public void setUser_name(String user_name) {
		this.user_name = user_name;
	}
	public String getUser_password() {
		return user_password;
	}
	public void setUser_password(String user_password) {
		this.user_password = user_password;
	}
	public String getUser_state() {
		return user_state;
	}
	public void setUser_state(String user_state) {
		this.user_state = user_state;
	}
	@Override
	public String toString() {
		return "User [user_id=" + user_id + ", user_code=" + user_code + ", user_name=" + user_name + ", user_password="
				+ user_password + ", user_state=" + user_state + "]";
	}
	

}

编写Role.java

package com.web.domain;

import java.util.HashSet;
import java.util.Set;

public class Role {
private Long role_id;
private String role_name;
private String role_memo;
//set集合来存放多个用户
private Set<User> users=new HashSet<User>();
public Set<User> getUsers() {
	return users;
}
public void setUsers(Set<User> users) {
	this.users = users;
}
public Long getRole_id() {
	return role_id;
}
public void setRole_id(Long role_id) {
	this.role_id = role_id;
}
public String getRole_name() {
	return role_name;
}
public void setRole_name(String role_name) {
	this.role_name = role_name;
}
public String getRole_memo() {
	return role_memo;
}
public void setRole_memo(String role_memo) {
	this.role_memo = role_memo;
}
@Override
public String toString() {
	return "Role [role_id=" + role_id + ", role_name=" + role_name + ", role_memo=" + role_memo + "]";
}


}

2.3. 用户和角色的映射配置文件如下

编写User.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>
<!-- javabean与表之间的对应关系 -->
<class name="com.web.domain.User" table="sys_user">
<!-- 主键对应 -->
<id name="user_id" column="user_id">
<!-- 主键策略(与自增长相关) -->
<generator class="native"></generator>
</id>
<!-- 其他字段 -->
<property name="user_code" column="user_code"></property>
<property name="user_name" column="user_name"></property>
<property name="user_password" column="user_password"></property>
<property name="user_state" column="user_state"></property>
<!-- 配置多对多 -->
<!-- name:User类多roles的属性
	table:中间表的名称 -->
	<set name="roles" table="sys_user_role">
	<!-- column="user_id"指的是中间表用户的外键 -->
	<key column="user_id"></key>
	<!-- 配置角色表信息 -->
	<!-- column="role_id" 中间表角色的外键 -->
	<many-to-many class="com.web.domain.Role" column="role_id"></many-to-many>
	</set>
</class>
</hibernate-mapping>

编写Role.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>
<!-- javabean与表之间的对应关系 -->
<class name="com.web.domain.Role" table="sys_role">
<!-- 主键对应 -->
<id name="role_id" column="role_id">
<!-- 主键策略(与自增长相关) -->
<generator class="native"></generator>
</id>
<!-- 其他字段 -->
<property name="role_name" column="role_name"></property>
<property name="role_memo" column="role_memo"></property>
<!-- 配置多对多 -->
<!-- name:Role类多users的属性
	table:中间表的名称 -->
	<set name="users" table="sys_user_role">
	<!-- column="role_id"指的是中间表角色的外键 -->
	<key column="role_id"></key>
	<!-- 配置用户表信息 -->
	<!-- column="user_id" 中间表用户的外键 -->
	<many-to-many class="com.web.domain.User" column="user_id"></many-to-many>
	</set>
</class>
</hibernate-mapping>

2.4. hibernate.cfg.xml配置文件引入映射文件

<mapping resource="com/web/domain/User.hbm.xml" />
<mapping resource="com/web/domain/Role.hbm.xml" />

角色也是如此。

2.5. 技术分析之多对多的及联保存——双向

修改User.hbm.xml

<set name="roles" table="sys_user_role" inverse="true" >
			<!-- column="user_id"指的是中间表用户的外键 -->
			<key column="user_id"></key>
			<!-- 配置角色表信息 -->
			<!-- column="role_id" 中间表角色的外键 -->
			<many-to-many class="com.web.domain.Role"
				column="role_id"></many-to-many>
		</set>

编写测试方法

@Test
	public void testSave() {
		Session session=HibernateUtil.getCurrentSession();
		Transaction transaction=session.beginTransaction();
		//新建两个用户
		User user1=new User();
		user1.setUser_name("张艺兴");
		User user2=new User();
		user2.setUser_name("王一博");
		//新建两个角色
		Role role1=new Role();
		role1.setRole_name("演员");
		Role role2=new Role();
		role2.setRole_name("歌手");
		//张艺兴演员+歌手
		user1.getRoles().add(role1);
		user1.getRoles().add(role2);
		role1.getUsers().add(user1);
		role1.getUsers().add(user2);
		//王一博演员
		user2.getRoles().add(role1);
		role1.getUsers().add(user2);
		//保存操作
		session.save(user1);
		session.save(user2);
		session.save(role1);
		session.save(role2);
		transaction.commit();
	}

测试运行

2.6. 技术分析之多对多的及联保存——单向

修改User.hbm.xml

<set name="roles" table="sys_user_role"  cascade="save-update">
			<!-- column="user_id"指的是中间表用户的外键 -->
			<key column="user_id"></key>
			<!-- 配置角色表信息 -->
			<!-- column="role_id" 中间表角色的外键 -->
			<many-to-many class="com.web.domain.Role"
				column="role_id"></many-to-many>
		</set>

编写测试方法

//及联保存 单向
		@Test
		public void testSave1() {
			Session session=HibernateUtil.getCurrentSession();
			Transaction transaction=session.beginTransaction();
			//新建两个用户
			User user1=new User();
			user1.setUser_name("张艺兴1");
			User user2=new User();
			user2.setUser_name("王一博1");
			//新建两个角色
			Role role1=new Role();
			role1.setRole_name("演员1");
			Role role2=new Role();
			role2.setRole_name("歌手1");
			//张艺兴1演员1+歌手1
			user1.getRoles().add(role1);
			user1.getRoles().add(role2);
			//王一博1演员
			user2.getRoles().add(role1);
			//保存操作 只保存用户
			session.save(user1);
			session.save(user2);
			transaction.commit();
		}

测试结果

2.7. 及联删除(在多对多中是很少使用的)

编写测试方法

// 及联删除
	@Test
	public void testDelete() {
		Session session = HibernateUtil.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		// 获取id为10的用户王一博1
		User user = session.get(User.class, 10L);
		// 获取id为9的角色演员1
		Role role = session.get(Role.class, 9L);
		// 王一博1不再是演员1,解除关系
		user.getRoles().remove(role);
		// 使用快照机制
		transaction.commit();
	}

测试结果

注意:千万不要在映射文件中配置cascade="delete",否则在删除一个用户时会把关联的角色删除,导致其他用户无法关联到角色

【示例】

修改User.hbm.xml

<set name="roles" table="sys_user_role"  cascade="delete">
			<!-- column="user_id"指的是中间表用户的外键 -->
			<key column="user_id"></key>
			<!-- 配置角色表信息 -->
			<!-- column="role_id" 中间表角色的外键 -->
			<many-to-many class="com.web.domain.Role"
				column="role_id"></many-to-many>
		</set>

修改Role.hbm.xml

<set name="users" table="sys_user_role" cascade="delete">
	<!-- column="role_id"指的是中间表角色的外键 -->
	<key column="role_id"></key>
	<!-- 配置用户表信息 -->
	<!-- column="user_id" 中间表用户的外键 -->
	<many-to-many class="com.web.domain.User" column="user_id"></many-to-many>
	</set>

编写测试方法

// 及联删除的错误示范
		@Test
		public void testDelete1() {
			Session session = HibernateUtil.getCurrentSession();
			Transaction transaction = session.beginTransaction();
			// 获取id为3的用户张艺兴
			User user = session.get(User.class, 3L);
			// 删除张艺兴用户
			session.delete(user);
			transaction.commit();
		}

测试结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值