(07)Hibernate的inverse属性和cascade属性

Hibernate中的inverse和cascade,这两个属性都用于一多对(one-to-many)或者多对多(many-to-many)的关系中。

概括的来说,inverse代表是否由己方维护关系,cascade代表是否执行级联操作。接下来,举一列子来更加详细的说明这一关系。

假设有T_Department(部门表)和T_Employee(员工表),它们存在一对多的关系。表的定义如下:

create table T_Department(
    id int auto_increment,
    name varchar(20),
    primary key(id) -- 主键
)

create table T_Employee(
    id int auto_increment,
    name varchar(20),
    salary int,
    deptId int,
    primary key(id), -- 主键
    key fk_emp_dept (deptId),-- 外键
    constraint cons_emp_dept foreign key(deptId) references T_Department(id) on update cascade on delete cascade -- 外键约束
)

一个部门里面,可以有多个员工,也就是1:N的关系。这个1:N的关系是通过T_Department的主键id和T_Employee的外键deptId关联实现的。

(1)Hibernate是一个ORM框架,实现了Java对象与数据表之间的映射。上面谈到的T_Department和T_Employee是数据库中的表,在Hibernate中也存在相应的JavaBean类与两个表相对应,即Department类和Employee类。

Department.java

package com.rk.hibernate.g_one2Many;

import java.util.Set;

public class Department
{
	private int deptId;
	private String deptName;
	private Set<Employee> emps;
	public int getDeptId()
	{
		return deptId;
	}
	public void setDeptId(int deptId)
	{
		this.deptId = deptId;
	}
	public String getDeptName()
	{
		return deptName;
	}
	public void setDeptName(String deptName)
	{
		this.deptName = deptName;
	}
	public Set<Employee> getEmps()
	{
		return emps;
	}
	public void setEmps(Set<Employee> emps)
	{
		this.emps = emps;
	}
	@Override
	public String toString()
	{
		return "Department [deptId=" + deptId + ", deptName=" + deptName + "]";
	}
}

Department.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 package="com.rk.hibernate.g_one2Many" auto-import="true">
	<class name="Department" table="T_Department">
		<id name="deptId" column="id">
			<generator class="native"></generator>
		</id>
		<property name="deptName" column="name" type="string"></property>
		<set name="emps" table="T_Employee" inverse="true" cascade="save-update,delete">
			<key column="deptId"></key>
			<one-to-many class="Employee"/>
		</set>
	</class>
</hibernate-mapping>

Employee.java

package com.rk.hibernate.g_one2Many;

public class Employee
{
	private int empId;
	private String empName;
	private double salary;
	private Department dept;
	public int getEmpId()
	{
		return empId;
	}
	public void setEmpId(int empId)
	{
		this.empId = empId;
	}
	public String getEmpName()
	{
		return empName;
	}
	public void setEmpName(String empName)
	{
		this.empName = empName;
	}
	public double getSalary()
	{
		return salary;
	}
	public void setSalary(double salary)
	{
		this.salary = salary;
	}
	public Department getDept()
	{
		return dept;
	}
	public void setDept(Department dept)
	{
		this.dept = dept;
	}
	@Override
	public String toString()
	{
		return "Employee [empId=" + empId + ", empName=" + empName + ", salary=" + salary + "]";
	}

}

Employee.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 package="com.rk.hibernate.g_one2Many" auto-import="true">
	<class name="Employee" table="T_Employee">
		<id name="empId" column="id">
			<generator class="native"></generator>
		</id>
		<property name="empName" column="name"></property>
		<property name="salary" column="salary"></property>
		<many-to-one name="dept" column="deptId" class="Department"></many-to-one>
	</class>
</hibernate-mapping>

(2)Hibernate是一个ORM框架,实现了Java对象与数据表之间的映射(我明白自己在重复这句话)。在Hibernate中,虽然它操作的对象是JavaBean类(例如Department类和Employee类),但最终会转换为对数据库中表(例如,T_Department和T_Employee)的操作。

(3)在上面谈到,T_Department和T_Employee两个表存在1:N的关系,那么在Department类和Employee类的实例(instance)当中,也应该体现出这种关系。在T_Employee表中,有外键字段deptId,因此由T_Employee表对应的Employee类来维护这处关联关系是“理所当然”的。

(4)Hibernate,不只是让“理所当然”的事情实现就行了,它提供了更强大的功能,就是可以让Department类来维护T_Department和T_Employee两个表之间的关联关系。当然,Hibernate提供的这个功能是可选的,开发者可以使用,也可以不使用。这个功能以inverse属性的形式存在于Hibernate的映射文件中,它代表的是维护两表之间relationship的权限(权力):inverse="false"表示不进行反转,也就是拥有维护两表之间relationship的权力;inverse="true"表示进行反转,不具有维护两表这间relationship的权力。

(5)再说直白一些就是,当我们保存Department类的实例对象时,如果Deparment类的实例与某几个Employee类的对象之间有关联,那么Hibernate会根据inverse的值来决定是否更新T_Employee表中的deptId字段。注意:正常情况下,如果保存Employee的对象,更新T_Employee表中的deptId字段,是正常的,是无可厚非的;现在的情况是,保存Deparment类的实例对象,而对T_Employee表的deptId进行更新,它这样做的目的就是为了维护两个表之间关系。

(6)inverse属性控制的是维护两个表之间关系,而cascade属性控制的是“是否更改另一个表的内容”。在上面的例子中,inverse可能只是控制Department类是否可以更新T_Employee表的deptId字段,而cascade属性是控制是否可以在T_Employee表中添加或删除一条数据记录;inverse只影响一个字段,而cascade影响一行数据。

1、inverse属性

Inverse Attribute有时被称为Relationship Owner。

应用场景:When we are talking about one-to-many or many-to-many relationships, one of the sides should take the responsibility of managing the relationship. (当我们谈到1对多、多对多关系时,其中一方需要维护它们之间的映射关系。inverse属性的应用场景是1对多(one-to-many)或多对多(many-to-many),在多对1(many-to-one)的情形中用不到。)

默认值:Note that the inverse="false" is actually a default, so you can skip providing the inverse attribute if you wish to set the inverse relationship to false.(注意:inverse的默认值是false。)

inverse属性对操作的影响
序号 操作类型 是否影响 具体说明
1 保存数据 有影响
如果设置控制反转,即inverse=true, 然后通过部门方维护关联关系。在保存部门的时候,同时保存员工,数据会保存,但关联关系不会维护。即外键字段deptId为NULL

2 获取数据 获取数据只是参照两个表之间的关系,并不会对这种关系进行修改,因此获取数据不会受到影响。
3 解除关联关系 有影响
inverse=false,  可以解除关联

inverse=true,  当前方(部门)没有控制权,不能解除关联关系。(不会生成update语句,也不会报错)

4 删除数据 有影响
inverse=false, 有控制权, 可以删除。先清空外键引用,再删除数据。

inverse=true,  没有控制权: 如果删除的记录有被外键引用,会报错,违反主外键引用约束!  如果删除的记录没有被引用,可以直接删除。

App_Inverse.java

package com.rk.hibernate.g_one2Many;

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

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

public class App_Inverse
{
	private static SessionFactory sf;
	static
	{
		sf = new Configuration()
					.configure()
					.addClass(Department.class)
					.addClass(Employee.class)
					.buildSessionFactory();
	}

	//1. 是否设置inverse,对保存数据的影响?   有
	//如果inverse="false",则添加Deparment和Employee之间的关联关系
	//如果inverse="true",则不添加关联关系
	@Test
	public void testSave()
	{
		int i = 0;
		Session session = sf.openSession();
		session.beginTransaction();

		// 员工1
		Employee emp1 = new Employee();
		emp1.setEmpName("张小三" + i);
		emp1.setSalary(1000);

		// 员工2
		Employee emp2 = new Employee();
		emp2.setEmpName("李小四" + i);
		emp2.setSalary(800);

		// 部门
		Department dept = new Department();
		dept.setDeptName("部门" + i);
		Set<Employee> emps = new HashSet<Employee>();
		emps.add(emp1);
		emps.add(emp2);
		dept.setEmps(emps);// inverse=true, 不会设置关联关系。此时的关联应该通过员工方维护

		session.save(dept);
		session.save(emp1);
		session.save(emp2);

		session.getTransaction().commit();
		session.close();
		System.out.println("执行结束!");
	}

	//2. 是否设置inverse,对获取数据的影响?   无.
	@Test
	public void testGet()
	{
		Session session = sf.openSession();
		session.beginTransaction();

		Department dept = (Department) session.get(Department.class, 2);
		System.out.println(dept.getDeptId());
		System.out.println(dept.getDeptName());
		System.out.println(dept.getEmps());

		session.getTransaction().commit();
		session.close();
		System.out.println("执行结束!");
	}

	//3. 是否设置inverse,对关联关系的影响?   有
	//如果inverse="false",则删除Deparment和Employee之间的关联关系
	//如果inverse="true",则不可以删除关联关系
	@Test
	public void testClear()
	{
		Session session = sf.openSession();
		session.beginTransaction();

		// 获取部门
		Department dept = (Department) session.get(Department.class, 2);
		// 解除关系
		dept.getEmps().clear();

		session.getTransaction().commit();
		session.close();
		System.out.println("执行结束!");
	}

	//4. 是否设置inverse,对删除的影响?   有
	//如果inverse="false",则可删除Deparment和Employee之间的关联关系
	//如果inverse="true",则不可以删除关联关系。
	//								如果删除的记录有被外键引用,会报错,违反主外键引用约束!
	//								如果删除的记录没有被引用,可以直接删除。
	@Test
	public void testDelete()
	{
		Session session = sf.openSession();
		session.beginTransaction();

		// 获取部门
		Department dept = (Department) session.get(Department.class, 3);
		if (dept != null)
		{
			session.delete(dept);
		}

		session.getTransaction().commit();
		session.close();
		System.out.println("执行结束!");
	}
}

2、cascade属性


作用:When persisting object graphs, we usually have to issue save (or update) commands on individual entities. However, the  cascade attribute defined on the graph lets us save the whole graph without our having to worry about saving the entities one by one. Setting the cascading behavior can reduce the lines of code and make it more succinct. We only have to save the parent node; the rest of the graph is handled by Hibernate‘s runtime.

使用范围:The  cascade attribute is set on the collection attributes.

cascade 表示级联操作,它可能的值如下:

none          不级联操作, 默认值

save-update     级联保存或更新

delete  级联删除

save-update,delete    级联保存、更新、删除

all                 同上。级联保存、更新、删除

App_Cascade.java

package com.rk.hibernate.g_one2Many;

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

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

public class App_Cascade
{
	private static SessionFactory sf;
	static
	{
		sf = new Configuration()
					.configure()
					.addClass(Department.class)
					.addClass(Employee.class)
					.buildSessionFactory();
	}

	@Test
	public void testSave()
	{
		int i=4;
		Session session = sf.openSession();
		session.beginTransaction();

		//员工1
		Employee emp1 = new Employee();
		emp1.setEmpName("张小三" + i);
		emp1.setSalary(1000);

		//员工2
		Employee emp2 = new Employee();
		emp2.setEmpName("李小四" + i);
		emp2.setSalary(800);

		//部门
		Department dept = new Department();
		dept.setDeptName("部门" + i);
		Set<Employee> emps = new HashSet<Employee>();
		emps.add(emp1);
		emps.add(emp2);
		dept.setEmps(emps);

		session.save(dept);	//设置级联保存后,只需要保存dept对象
//		session.save(emp1);
//		session.save(emp2);

		session.getTransaction().commit();
		session.close();
		System.out.println("执行结束!");
	}

	@Test
	public void testDelete()
	{
		Session session = sf.openSession();
		session.beginTransaction();

		// 获取部门
		Department dept = (Department) session.get(Department.class, 3);
		if(dept != null)
		{
			session.delete(dept);// 级联删除
		}

		session.getTransaction().commit();
		session.close();
		System.out.println("执行结束!");
	}
}

3、hibernate常见面试题: inverse与cascade区别?

(1)谈到两者的区别,必须是两者有相近或相似之处

(2)inverse和cascade的相似之处是它们两个都出现在one-to-many和many-to-many的映射当中

(3)两者的区别是inverse是控制是否维护两表之间relationship,而cascade是控制是否进行级联操作。

(4)两者存在一个执行的前后关系:cascade在前,inverse在后,因为总是先有“数据”本身,再有“数据之间的关系”。cascade操作的是数据,而inverse操作的是关系。

Different between cascade and inverse

http://www.mkyong.com/hibernate/different-between-cascade-and-inverse/

时间: 2024-09-29 16:50:07

(07)Hibernate的inverse属性和cascade属性的相关文章

Hibernate inverse属性和cascade属性

Inverse属性 Inverse属性,是在维护关联关系的时候起作用的. 表示控制权是否转移.(在一的一方起作用) Inverse , 控制反转. Inverse = false  不反转:   当前方有控制权 True  控制反转: 当前方没有控制权 维护关联关系中,是否设置inverse属性: 1.保存数据                    有影响. 如果设置控制反转,即inverse=true, 然后通过部门方维护关联关系.在保存部门的时候,同时保存员工,数据会保存,但关联关系不会维护

Hibernate中inverse属性与cascade属性

Hibernate集合映射中,经常会使用到"inverse"和"cascade"这两个属性.对于我这样,Hibernate接触不深和语文水平够烂的种种因素,发现这两个属性实在是难以理解,无奈只好将这个两个属性解释工作交给了Google和Baidu,查看了许多牛人的解释,加上自己在Eclipse上的调试,对"inverse"和"cascade"这两个属性有了一定的见解. "inverse"属性探究 "

Hibernate inverse属性与cascade属性

理解: inverse属性为false的那一端,拥有管理关系维护的权利 cascade属性指级联,说的通俗点,在cascade那端指定的操作,会影响到所关联的对象 举个例子: 班级和学生的关系是一对多 班级class类包含id,名称和学生的Set集合 学生student类包含id,姓名和班级的id(外键) cascade属性:学生是依赖班级存在的,班级不存在,那么学生也不存在.也就是说,删除班级的同时,学生也就得删除,而不能反过来.一的那端删除时,多的那方已经没有意义了:而多的那端删除时,并不能

Hibernate【inverse和cascade属性】知识要点

Inverse属性 Inverse属性:表示控制权是否转移.. true:控制权已转移[当前一方没有控制权] false:控制权没有转移[当前一方有控制权] Inverse属性,是在维护关联关系的时候起作用的.只能在"一"的一方中使用该属性!Inverse属性的默认值为fasle,也就是当前一方是有控制权的 从一下的几个方面看看Inverse在维护关联关系时是否起作用: 保存数据 获取数据 解除关联关系 删除数据对关联关系的影响 保存数据 将inverse属性设置为ture,使dept

hibernate中 cascade属性详解

配置关联时,我们考虑两点:程序执行效率和实际业务需要,前面的例子中无论是单向的关联还是双向的关联,我们都要分别对实体类使用session.save()才能将数据保存至数据库.问题:如果保存数据非常多,那编码是一件恐怖的事情.有没有简单的方法呢?将<set>标签cascade=all总结:我们只对district对象执行了持久化操作,但是通过sql语句,我们发现street执行了持久啊操作,这就是cascade属性的作用.当设置cascade属性不none时,Hibernate会持久化所关联的对

一对多(多对一)关系中的inverse和cascade属性

首先说一下inverse: "inverse" 直译过来就是"反转,使颠倒"的意思,书面化的解释为"是否将关系维护的权力交给对方" 1. 在hibernate中inverse默认是false,也就是己方拥有维护关系的权利, 当然为true的话,就是把维护关系的权利交给了对方 2. 在一对多的关系(多对一)中,通常将一端的inverse设置为false(一端设为true的话会多出更新语句,有性能问题,下面会讲到),而多对多的关系中,inverse的

spring+hibernate实体类注解详解(非原创) + cascade属性取值

@Entity //继承策略.另一个类继承本类,那么本类里的属性应用到另一个类中 @Inheritance(strategy = InheritanceType.JOINED ) @Table(name="INFOM_TESTRESULT") public class TestResult extends IdEntity{} 1 @Entity(name="EntityName") 必须 name为可选,对应数据库中一的个表 2 @Table(name="

hibernate中inverse属性

inverse属性:是在维护关联关系的时候起作用的. 表示控制权是否转移(在一的一方起作用) inverse=false    不反转,当前方有控制权 inverse=true  控制反转,当前方没有控制权 保存数据:会影响到多的一方的数据 一的一方在保存数据时候 不会维护多的一方数据(多的一方数据不会保存到数据库中) 解除关联关系.clear()  方法 inverse=false  解除与多的一方关系  就是把多的一方的外键设为null inverse=true   不会解除 删除关联关系

Hibernate Annotation关系映射, 级联cascade属性

Hibernate Annotation关系映射, 级联cascade属性一. Hibernate Annotation关系映射 1.一对一外键关联映射(单向) 2.一对一外键关联映射(双向) 3.一对一主键关联映射(不重要)在这不演示 在实际中很少用,使用注解@PrimaryKeyJoinColumn 意思是说,我的主键去参考另外一张表中的主键,作为我的主键,但是在我测试使用 注解一对一主键关联映射,在生成表的时候,数据库中并没有生成关联,使用XML 映射可以生成.Annotation注解一对