Hibernate_03

一、一对多|多对一

1.1、关系表达(多的一方存在外键)

                                                                         【图1-1 表中的表达】

 

                                                              【图 1-2 实体中的表达】

说明:其中Set集合避免了数据的重复

1.2、hibernate基本操作

重点:ORM元数据中的表达

【实体类:Customer.java】

//使用Set集合表示多的一方

private Set<LinkMan> linkMan = new HashSet<>();
    
    public Set<LinkMan> getLinkMan() {
        return linkMan;
    }
    public void setLinkMan(Set<LinkMan> linkMan) {
        this.linkMan = linkMan;
    }

package hibernate.hnu.domain;

import java.util.HashSet;
import java.util.Set;
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_linkman;
	private String cust_phone;
	private String cust_mobile;
	
	private Set<LinkMan> linkMan = new HashSet<>();
	
	public Set<LinkMan> getLinkMan() {
		return linkMan;
	}
	public void setLinkMan(Set<LinkMan> linkMan) {
		this.linkMan = linkMan;
	}
	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 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 + "]";
	}
	
	
	
}

【实体类:LinkMan.java】

准备数据库:

其中外键: `lkm_cust_id` bigint(32) NOT NULL COMMENT '客户id',

CREATE TABLE `cst_linkman` (
  `lkm_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)',
  `lkm_name` varchar(16) DEFAULT NULL COMMENT '联系人姓名',
  `lkm_cust_id` bigint(32) NOT NULL COMMENT '客户id',
  `lkm_gender` char(1) DEFAULT NULL COMMENT '联系人性别',
  `lkm_phone` varchar(16) DEFAULT NULL COMMENT '联系人办公电话',
  `lkm_mobile` varchar(16) DEFAULT NULL COMMENT '联系人手机',
  `lkm_email` varchar(64) DEFAULT NULL COMMENT '联系人邮箱',
  `lkm_qq` varchar(16) DEFAULT NULL COMMENT '联系人qq',
  `lkm_position` varchar(16) DEFAULT NULL COMMENT '联系人职位',
  `lkm_memo` varchar(512) DEFAULT NULL COMMENT '联系人备注',
  PRIMARY KEY (`lkm_id`),
  KEY `FK_cst_linkman_lkm_cust_id` (`lkm_cust_id`),
  CONSTRAINT `FK_cst_linkman_lkm_cust_id` FOREIGN KEY (`lkm_cust_id`) REFERENCES `cst_customer` (`cust_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

数据库对应的实体类;

注意:在实体类中不维护外键的属性,在配置文件中体现外键

//在多的一方维护 一的一方的属性
    private Customer customer;
    
    public Customer getCustomer() {
        return customer;
    }
    public void setCustomer(Customer customer) {
        this.customer = customer;
    }
package hibernate.hnu.domain;
public class LinkMan {

	private Long lkm_id;
	private String lkm_name;
	
	//外键,我们在配置文件中维护
	//private Long 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 Customer customer;
	
	public Customer getCustomer() {
		return customer;
	}
	public void setCustomer(Customer customer) {
		this.customer = customer;
	}
	public Long getLkm_id() {
		return lkm_id;
	}
	public void setLkm_id(Long 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;
	}
	
	@Override
	public String toString() {
		return "LinkMan [lkm_id=" + lkm_id + ", lkm_name=" + lkm_name + "]";
	}
	
	
}

【ORM元数据配置:Customer.hbm.xml】

<!-- 集合,一对多,在配置文件中的配置  -->
        <!--
            name属性:实体类中多的一方的属性名
            column:外键列名
            class:与我关联的对象的完整类名
         -->
        
        <set name="linkMan">
            <key column="lkm_cust_id"></key>
            <one-to-many class="LinkMan"/>
        </set>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >

<hibernate-mapping package="hibernate.hnu.domain">
	<class name="hibernate.hnu.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_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属性:实体类中多的一方的属性名
			column:外键列名
		    class:与我关联的对象的完整类名
		 -->
		
		<set name="linkMan">
			<key column="lkm_cust_id"></key>
			<one-to-many class="LinkMan"/>
		</set>
	
	</class>

</hibernate-mapping>

【ORM元数据配置:LinkMan.hbm.xml】

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >

<hibernate-mapping package="hibernate.hnu.domain">
	<class name="hibernate.hnu.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>
	
		
		<!-- 多对一 -->
		<!-- 
			name属性:实体类中一的一方的属性名
			column:外键列名
		    class:与我关联的对象的完整类名
		 -->
		<many-to-one name="customer" column="lkm_cust_id" class="Customer"></many-to-one>
	
	</class>

</hibernate-mapping>

【hibernate主配置文件:hibernate.cfg.xml】

主配置文件别忘记导入linkMan.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration SYSTEM "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd" >

<hibernate-configuration>

<!-- hibernate.properties文件中搜索配置信息 -->
<!-- 5个必选配置 -->

  <session-factory>
  	<!-- 数据库驱动 -->
  	<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
  	<!-- 数据库url -->
  	<property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
  	<!-- 数据库链接用户名 -->
  	<property name="hibernate.connection.username">root</property>
  	<!-- 数据库链接密码 -->
  	<property name="hibernate.connection.password">123456</property>
  	<!-- 数据库方言-->
  	<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
 

 <!-- 3个可选配置 -->

 	<!-- 将hibernate生成sql语句打印到控制台 -->
    <property name="hibernate.show_sql">true</property>
    
    <!-- 将hibernate生成sql语句进行格式化,即语法缩进 -->
  	<property name="hibernate.format_sql">true</property>
  
	<!--自动生成表,如果已经存在则不会再生成,如果表有变动,自动更新表(不会删除任何数据)--> 	 
  	<property name="hibernate.hbm2ddl.auto">update</property>


 <!-- 根据业务调整配置 -->
 
    <!-- 指定hibernate的隔离级别;-->
	<property name="hibernate.connection.isolation">4</property>

	<!-- 指定session与当前线程绑定 -->   
    <property name="hibernate.current_session_context_class">thread</property>
    

<!-- 引入orm元数据-->	
	<mapping resource="hibernate/hnu/domain/Customer.hbm.xml"/>
	<mapping resource="hibernate/hnu/domain/LinkMan.hbm.xml"/>
  </session-factory>
</hibernate-configuration>

【测试:OneManyTest.java】

package hibernate.hnu.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import hibernate.hnu.domain.Customer;
import hibernate.hnu.domain.LinkMan;
import hibernate.hnu.utils.HibernateUtils;

public class OneManyTest {

	@Test
	public void function(){
		//获得session
		Session session = HibernateUtils.openSession();
		
		//开启事务
		Transaction transaction = session.beginTransaction();
		
		//创建对象
		Customer c = new Customer();
		c.setCust_name("蜀国");
		
		LinkMan m1 = new LinkMan();
		m1.setLkm_name("刘备");
		LinkMan m2 = new LinkMan();
		m2.setLkm_name("关羽");
		
		//表达一对多,客户下有多个联系人
		c.getLinkMan().add(m1);
		c.getLinkMan().add(m2);
		
		//表达多对一,多个联系人指向同一个客户
		m1.setCustomer(c);
		m2.setCustomer(c);
		
		session.save(c);
		session.save(m1);
		session.save(m2);
		
		transaction.commit();
		session.close();
		
	}
}

【查看数据库】

【为客户添加联系人】

package hibernate.hnu.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import hibernate.hnu.domain.Customer;
import hibernate.hnu.domain.LinkMan;
import hibernate.hnu.utils.HibernateUtils;

public class OneManyTest {

	@Test
	public void function(){
		//获得session
		Session session = HibernateUtils.openSession();
		
		//开启事务
		Transaction transaction = session.beginTransaction();
		//----------------------------------------------------
		
		//获取数据库中的客户
		Customer customer = session.get(Customer.class, 1L);
		
		//创建联系人
		LinkMan linkMan = new LinkMan();
		linkMan.setLkm_name("张飞");
		
		//将联系人添加到客户
		customer.getLinkMan().add(linkMan);
		
		//将客户添加到联系人
		linkMan.setCustomer(customer);
		
		session.save(linkMan);
		
		//---------------------------------------------------
	
		transaction.commit();
		session.close();
		
	}
}

【查看数据库】

【为客户删除联系人】

package hibernate.hnu.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import hibernate.hnu.domain.Customer;
import hibernate.hnu.domain.LinkMan;
import hibernate.hnu.utils.HibernateUtils;

public class OneManyTest {

	@Test
	public void function(){
		//获得session
		Session session = HibernateUtils.openSession();
		
		//开启事务
		Transaction transaction = session.beginTransaction();
		//----------------------------------------------------
		
		//获取数据库中的客户
		Customer customer = session.get(Customer.class, 1L);
		
		//获取联系人
		LinkMan linkMan = session.get(LinkMan.class, 2L);
		
		//将联系人从客户中移除
		customer.getLinkMan().remove(linkMan);
		
		//将删除的联系人的客户置空
		linkMan.setCustomer(null);
		
		/************************************************
		
		 注意:这里的customer和linkMan都是持久化状态,无需进一步操作
		 
		 *************************************************/
		
		//---------------------------------------------------
	
		//提交事务
		transaction.commit();
		
		//关闭资源
		session.close();
		
	}
}

【查看数据库】

1.3、hibernate进阶操作之级联操作

【一的一方.hbm.xml文件下】

【Customer.hbm.xml】

【级联保存】

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >

<hibernate-mapping package="hibernate.hnu.domain">
	<class name="hibernate.hnu.domain.Customer" table="cst_customer">
		<id name="cust_id" column="cust_id">
			
			<!--generator;主键生成策略  
			
			就是每条记录录入时,主键的生成规则
				identity:主键自增,由数据库维护主键值,录入时不需要指定主键
				sequence:Oracre中的主键生成策略
				increment(了解):主键自增,由hibernate来维护,每次插入时会先查询表中id最大值,+1作为主键
				hilo(了解):高级应用算法,主键自增,由hibernate来维护,开发时不使用
				native:hilo+sequence+identity 自动三选一策略
				uuid:产生随机字符串作为主键,组件类型必须是String类型
				assigned:自然主键生成策略。hibernate不会管理主键值,由开发人员手动录入主键
			-->

			<generator class="native"></generator>
		</id>
		
		<property name="cust_name" column="cust_name"></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>
	
		<!-- 级联操作:cascade
		 	save-update : 级联保存更新
		 	delete : 级联删除
		 	all: save-update+delete
	   			级联操作:简化操作,简化代码,目的就是少写两行代码
	 	-->
		<set name="linkMan" cascade="save-update">
			<key column="lkm_cust_id"></key>
			<one-to-many class="LinkMan"/>
		</set>
	
	</class>

</hibernate-mapping>

【测试代码】

package hibernate.hnu.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import hibernate.hnu.domain.Customer;
import hibernate.hnu.domain.LinkMan;
import hibernate.hnu.utils.HibernateUtils;

public class OneManyTest {

	@Test
	public void function(){
		//获得session
		Session session = HibernateUtils.openSession();
		
		//开启事务
		Transaction transaction = session.beginTransaction();
		//----------------------------------------------------
		
		//创建客户对象
		Customer customer = new Customer();
		customer.setCust_name("魏国");
		
                //创建联系人对象
		LinkMan linkMan1 = new LinkMan();
		linkMan1.setLkm_name("曹操");
		
		LinkMan linkMan2 = new LinkMan();
		linkMan2.setLkm_name("夏侯惇");
		
		
		customer.getLinkMan().add(linkMan1);
		customer.getLinkMan().add(linkMan2);
		
		//多个联系人对应同一个客户
		linkMan1.setCustomer(customer);
		linkMan2.setCustomer(customer);
		
		//由于在一的一方设置了级联
		//所以只需要将一的一方变成持久化状态即可
		session.save(customer);
		
		//下面两行代码就可以省略了
		
//		session.save(linkMan1);
//		session.save(linkMan2);
		
		
		//---------------------------------------------------
	
		//提交事务
		transaction.commit();
		
		//关闭资源
		session.close();
		
	}
}

【数据库结果】

 

【级联删除】

就是将cascade对应的属性由原来的save-update 改成 delete

<set name="linkMan" cascade="delete">
	<key column="lkm_cust_id"></key>
	<one-to-many class="LinkMan"/>
</set>

【测试代码】

package hibernate.hnu.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import hibernate.hnu.domain.Customer;
import hibernate.hnu.domain.LinkMan;
import hibernate.hnu.utils.HibernateUtils;

public class OneManyTest {

	@Test
	public void function(){
		//获得session
		Session session = HibernateUtils.openSession();
		
		//开启事务
		Transaction transaction = session.beginTransaction();
		//----------------------------------------------------
		
		//获得要操作的客户的对象
		Customer customer = session.get(Customer.class, 1L);
		
		//调用delete方法删除客户
		session.delete(customer);
		
		
		//---------------------------------------------------
	
		//提交事务
		transaction.commit();
		
		//关闭资源
		session.close();
		
	}
}

【数据库】

 

【多的一方.hbm.xml文件下】

【LinkMan.hbm.xml】

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >

<hibernate-mapping package="hibernate.hnu.domain">
	<class name="hibernate.hnu.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>
	
		<!--多的一方:
			级联操作:cascade
		 	save-update : 级联保存更新
		 	delete : 级联删除
		 	all:save-update+delete
	   			级联操作:简化操作,简化代码,目的就是少写两行代码
	 	-->
		<many-to-one name="customer" column="lkm_cust_id" 
		 cascade="save-update" class="Customer"></many-to-one>
	
	</class>

</hibernate-mapping>

【测试代码】

package hibernate.hnu.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import hibernate.hnu.domain.Customer;
import hibernate.hnu.domain.LinkMan;
import hibernate.hnu.utils.HibernateUtils;

public class OneManyTest {

	@Test
	public void function(){
		//获得session
		Session session = HibernateUtils.openSession();
		
		//开启事务
		Transaction transaction = session.beginTransaction();
		//----------------------------------------------------
		
		//创建客户
		Customer customer = new Customer();
		customer.setCust_name("京东");
		
		//创建联系人
		LinkMan linkMan = new LinkMan();
		linkMan.setLkm_name("刘强东");

		//为客户设置联系人
		customer.getLinkMan().add(linkMan);
		
		//联系人属于哪个客户
		linkMan.setCustomer(customer);
		
		session.save(linkMan);
		
		//---------------------------------------------------
	
		//提交事务
		transaction.commit();
		
		//关闭资源
		session.close();
		
	}
}

【数据库】

结论:级联就是少写两行代码,只要持久化一方,与之关联的另一方也会被同步到数据库中。

建议cascade属性设置成save-update,不推荐使用delete

 

1.4、hibernate进阶操作之关系维护

删除Customer.hbm.xmlLinkMan.hbm.xml两个文件中的级联操作属性;

【执行代码】

package hibernate.hnu.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import hibernate.hnu.domain.Customer;
import hibernate.hnu.domain.LinkMan;
import hibernate.hnu.utils.HibernateUtils;

public class OneManyTest {

	@Test
	public void function(){
		//获得session
		Session session = HibernateUtils.openSession();
		
		//开启事务
		Transaction transaction = session.beginTransaction();
		//----------------------------------------------------
		
		//创建客户
		Customer customer = new Customer();
		customer.setCust_name("阿里巴巴");
		
		//创建联系人
		LinkMan linkMan1 = new LinkMan();
		linkMan1.setLkm_name("马云");
		
		LinkMan linkMan2 = new LinkMan();
		linkMan2.setLkm_name("李勇");

		//为客户设置联系人
		customer.getLinkMan().add(linkMan1);
		customer.getLinkMan().add(linkMan2);
		
		//联系人属于哪个客户
		linkMan1.setCustomer(customer);
		linkMan2.setCustomer(customer);
		
		session.save(customer);
		session.save(linkMan1);
		session.save(linkMan2);
		
		//---------------------------------------------------
	
		//提交事务
		transaction.commit();
		
		//关闭资源
		session.close();
		
	}
}

【控制台】

Hibernate: 
    update
        cst_linkman 
    set
        lkm_cust_id=? 
    where
        lkm_id=?
Hibernate: 
    update
        cst_linkman 
    set
        lkm_cust_id=? 
    where
        lkm_id=?

在保存时,两方都会维护外键关系,关系维护两次,冗余了,多余的维护关系语句,显然是客户这一端在维护关系。

【让一的一方放弃关系维护】

【Customer.hbm.xml】

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >

<hibernate-mapping package="hibernate.hnu.domain">
	<class name="hibernate.hnu.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_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>
	
		<!-- inverse属性:配置关系不维护 
		 	true:Customer不维护关系
		 	false(默认):Customer维护关系
		 	
		 	inverse属性:性能优化,提高关系维护的性能
	 	--> 
	 
		<!-- 
			多的一方,LinkMan,不能放弃维护关系,外键字段在多的一方
		-->
	 
		<!-- 
			原则:无论怎么放弃,总有一方必须维护关系,
			一对多的关系中:一的一方放弃,也只能一方放弃,多的一方不能放弃
		-->

		<set name="linkMan" inverse="true">
			<key column="lkm_cust_id"></key>
			<one-to-many class="LinkMan"/>
		</set>
	
	</class>

</hibernate-mapping>

控制台就干净了,一的一方不再维护外键,让多的一方去维护关系

为了节省数据库资源,省却不必要的update语句,我们一般建议在一对多双向关联关系中,将一方的inverse属性设置为true,即将主外键的关系交由多方来维护。

打个比方:在一个公司中,是老板认识所有的员工容易,还是所有员工认识老板容易?

 

二、多对多

2.1、关系表达

                                                                                【图 2-1 表中的表达】

                                                                              【图 2-2 实体中的表达】

2.2、多对多hibernate基本操作

ORM元数据

【数据库:sys_user】

CREATE TABLE `sys_user` (
  `user_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '用户id',
  `user_code` varchar(32) NOT NULL COMMENT '用户账号',
  `user_name` varchar(64) NOT NULL COMMENT '用户名称',
  `user_password` varchar(32) NOT NULL COMMENT '用户密码',
  `user_state` char(1) NOT NULL COMMENT '1:正常,0:暂停',
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;

【实体类:User.java】

package hibernate.hnu.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 Character user_state;
	
	//表达多对多
	private Set<Role> roles = new HashSet<>();

	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 Character getUser_state() {
		return user_state;
	}

	public void setUser_state(Character user_state) {
		this.user_state = user_state;
	}

	public Set<Role> getRoles() {
		return roles;
	}

	public void setRoles(Set<Role> roles) {
		this.roles = roles;
	}

	@Override
	public String toString() {
		return "User [user_id=" + user_id + ", user_name=" + user_name + "]";
	}
	
	
	
}

【数据库sys_role】

CREATE TABLE `sys_role` (
  `role_id` bigint(32) NOT NULL AUTO_INCREMENT,
  `role_name` varchar(32) NOT NULL COMMENT '角色名称',
  `role_memo` varchar(128) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

【实体类:Role.java】

package hibernate.hnu.domain;

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

public class Role {

	private Long role_id;
	private String role_name;
	private String role_memo;
	
	//表达多对多
	private Set<User> users = new HashSet<>();

	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;
	}

	public Set<User> getUsers() {
		return users;
	}

	public void setUsers(Set<User> users) {
		this.users = users;
	}

	@Override
	public String toString() {
		return "Role [role_id=" + role_id + ", role_name=" + role_name + "]";
	}
	
}

【User.hbm.xml和Role.hbm.xml】

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="hibernate.hnu.domain">
	<class name="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:对应实体类中多对多属性名
		table:配置中间表名
			key
				|-column:外键,别人引用“我”的外键,就是本实体类的主键
				
			many-to-many	
				|-class:我与哪个类是多对多关系
				|-column:外键,我引用别人的外键列名
				
	 -->	
	
	<set name="roles" table="user_role_id">
		<key column="user_id"></key>
		<many-to-many class="Role" column="role_id"></many-to-many>
	</set>	
	</class>

</hibernate-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="hibernate.hnu.domain">
	<class name="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:对应实体类中多对多属性名
		table:配置中间表名
			key
				|-column:外键,别人引用“我”的外键,就是本实体类的主键
				
			many-to-many	
				|-class:我与哪个类是多对多关系
				|-column:外键,我引用别人的外键列名
				
	 -->	
	<set name="users" table="user_role_id">
		<key column="role_id"></key>
		<many-to-many class="User" column="user_id"></many-to-many>
	</set>
	
	</class>
</hibernate-mapping>

【hibernate配置文件:hibernate.cfg.xml】

引入刚刚的ORM元数据

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration SYSTEM "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd" >

<hibernate-configuration>

<!-- hibernate.properties文件中搜索配置信息 -->
<!-- 5个必选配置 -->

  <session-factory>
  	<!-- 数据库驱动 -->
  	<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
  	<!-- 数据库url -->
  	<property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
  	<!-- 数据库链接用户名 -->
  	<property name="hibernate.connection.username">root</property>
  	<!-- 数据库链接密码 -->
  	<property name="hibernate.connection.password">123456</property>
  	<!-- 数据库方言-->
  	<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
 

 <!-- 3个可选配置 -->

 	<!-- 将hibernate生成sql语句打印到控制台 -->
    <property name="hibernate.show_sql">true</property>
    
    <!-- 将hibernate生成sql语句进行格式化,即语法缩进 -->
  	<property name="hibernate.format_sql">true</property>
  
	<!--自动生成表,如果已经存在则不会再生成,如果表有变动,自动更新表(不会删除任何数据)--> 	 
  	<property name="hibernate.hbm2ddl.auto">update</property>


 <!-- 根据业务调整配置 -->
 
    <!-- 指定hibernate的隔离级别;-->
	<property name="hibernate.connection.isolation">4</property>

	<!-- 指定session与当前线程绑定 -->   
    <property name="hibernate.current_session_context_class">thread</property>
    

<!-- 引入orm元数据-->	
	<mapping resource="hibernate/hnu/domain/Customer.hbm.xml"/>
	<mapping resource="hibernate/hnu/domain/LinkMan.hbm.xml"/>
	<mapping resource="hibernate/hnu/domain/User.hbm.xml"/>
	<mapping resource="hibernate/hnu/domain/Role.hbm.xml"/>
  
  </session-factory>
</hibernate-configuration>

2.3、多对多hibernate操作之关系维护操作

根据业务方向,选择哪一方放弃关系维护,这里角色放弃关系维护

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="hibernate.hnu.domain">
	<class name="Role" table="sys_role">
		<id name="role_id" column="role_id">
			<generator class=""></generator>
		</id>
	<property name="role_name" column="role_name"></property>
	<property name="role_memo" column="role_memo"></property>
	
	<!-- 多对多关系表达 -->
	<!-- 使用inverse属性:不维护关系
		true: 放弃维护关系
		false(默认):维护关系
		结论:将来开发中,如果遇到多对多关系时,一定要选择一方放弃维护关系
			一般谁来放弃要看业务方向,例如录入员工时,需要为员工指定所属角色
			那么业务方向就是由员工来维护角色,角色不需要维护与员工关系,角色放弃维护
			
			就是问自己:员工没了,要角色也就没用了
	 -->
	<set name="users" table="user_role_id" inverse="true">
		<key column="role_id"></key>
		<many-to-many class="User" column="user_id"></many-to-many>
	</set>
	
	</class>
</hibernate-mapping>

【测试代码】

package hibernate.hnu.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import hibernate.hnu.domain.Role;
import hibernate.hnu.domain.User;
import hibernate.hnu.utils.HibernateUtils;

public class ManyToManyTest {

	@Test
	public void function(){
		//1 获得session
		Session session = HibernateUtils.openSession();
				
		//2 开启事务
		Transaction tx = session.beginTransaction();
		
		//-----------------------------------------
		
		//创建两个User
		User user1 = new User();
		User user2 = new User();
		
		user1.setUser_name("商鞅");
		user2.setUser_name("司马错");
		
		Role role1 = new Role();
		Role role2 = new Role();
		
		role1.setRole_name("大良造");
		role2.setRole_name("上将军");
		
		//用户表达角色
		user1.getRoles().add(role1);
		user1.getRoles().add(role2);
		
		user2.getRoles().add(role2);
		
		//角色表达用户
		//(在不对xxx.hbm.xml修改时。两边都维护关系会造成主键重复的错误)
		//方法一:注释一方的关系维护代码,比如以下三行
		//方法二:在某一方主体配置表中设置inverse属性为true即可
		role1.getUsers().add(user1);
		role2.getUsers().add(user1);
		
		role2.getUsers().add(user2);
		
		
		//调用Save方法
		session.save(user1);
		session.save(user2);
		session.save(role1);
		session.save(role2);


		
		//--------------------------------------------
		
		//4 提交事务
		tx.commit();
		//5 关闭资源
		session.close();


	}
}

【数据库中的表】

2.4、多对多hibernate操作之级联操作

【User.hbm.xml】

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="hibernate.hnu.domain">
	<class name="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>

	<!-- 多对多关系表达 -->
	<!-- cascade级联操作:
			save-update : 级联保存
			delete :级联删除
			all : save-update+delete
		结论:cascade简化代码书写,该属性不使用无所谓,建议用只用save-update
			如果使用delete操作太过危险,尤其多对多中,不建议使用
	 -->

	<set name="roles" table="sys_user_role" cascade="save-update">
		<key column="user_id"></key>
		<many-to-many class="Role" column="role_id"></many-to-many>
	</set>	
	</class>

</hibernate-mapping>

【测试代码】

package hibernate.hnu.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import hibernate.hnu.domain.Role;
import hibernate.hnu.domain.User;
import hibernate.hnu.utils.HibernateUtils;

public class ManyToManyTest {

	@Test
	public void function(){
		//1 获得session
		Session session = HibernateUtils.openSession();
				
		//2 开启事务
		Transaction tx = session.beginTransaction();
		
		//-----------------------------------------
		
		//1> 获得司马错用户,user已经持久化
		User user = session.get(User.class, 2L);
		
		//2> 创建"上卿"角色
		Role role = new Role();
		role.setRole_name("上卿");
		
		//3> 将角色添加到用户中
		user.getRoles().add(role);
		
		
		//--------------------------------------------
		
		//4 提交事务
		tx.commit();
		//5 关闭资源
		session.close();


	}
}

【数据库】

改变成:

【级联删除】

package hibernate.hnu.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import hibernate.hnu.domain.Role;
import hibernate.hnu.domain.User;
import hibernate.hnu.utils.HibernateUtils;

public class ManyToManyTest {

	@Test
	public void function(){
		//1 获得session
		Session session = HibernateUtils.openSession();
				
		//2 开启事务
		Transaction tx = session.beginTransaction();
		
		//-----------------------------------------
		
		//获得司马错用户,user已经持久化
		User user = session.get(User.class, 2L);
		
		//获得 上将军 这个角色
		Role role = session.get(Role.class, 2L);
		
		//将角色从用户的角色集合中移除
		user.getRoles().remove(role);
		
		//--------------------------------------------
		
		//4 提交事务
		tx.commit();
		//5 关闭资源
		session.close();


	}
}

【数据库】

 

 

 

 

 

 

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/weixin_39464426/article/details/89293002
今日推荐