Hibernate单向多对一级联删除引发的问题

Hibernate单向多对一在级联删除时,会出现一些问题。

下面模拟我遇到的问题:

这次模拟与之前的一次模拟方法一直,博客:http://blog.csdn.net/openjdk8/article/details/38424403

模拟场景:有一个部门表t_dept,职位表t_position。

需求:当删除部门表时,不管职位表有没数据,照样删除。删除职位表就直接删除。

1,建表:

建表:

t_dept::部门表

t_position:职位表

CREATE TABLE t_dept(
   dept_id INT PRIMARY KEY auto_increment ,   #部门Id
   dept_name VARCHAR(45)                      #部门名字
) ;

CREATE TABLE t_position(
   position_id INT PRIMARY KEY auto_increment ,   #职位Id
   position_name VARCHAR(45) ,                    #职位名字
   dept_id INT ,                                  #外键
   CONSTRAINT fk_dept_position FOREIGN KEY(dept_id) REFERENCES t_dept(dept_id)
) ;

2,实体类(采用单向多对一):

Dept.java

package org.jian.domain;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;

@Entity
@Table(name = "t_dept")
public class Dept {
	private int id;
	private String name;

	@Id
	@GenericGenerator(name = "generator", strategy = "increment")
	@GeneratedValue(generator = "generator")
	@Column(name="dept_id")
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	@Column(name="dept_name")
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

}

Position.java

package org.jian.domain;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;

@Entity
@Table(name = "t_position")
public class Position {
	private int id;
	private String name;
	private Dept dept;

	@Id
	@GenericGenerator(name = "generator", strategy = "increment")
	@GeneratedValue(generator = "generator")
	@Column(name="position_id")
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	@Column(name="position_name")
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@ManyToOne(targetEntity = Dept.class, fetch = FetchType.LAZY, cascade = { CascadeType.ALL })
	@JoinColumn(name = "dept_id")
	public Dept getDept() {
		return dept;
	}

	public void setDept(Dept dept) {
		this.dept = dept;
	}

}

3,测试类:

package org.jian.domain;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

public class DeptTest {
private static SessionFactory sf ;

    @BeforeClass
    public static void beforeClass(){
    	sf = new AnnotationConfiguration().configure().buildSessionFactory() ;
    }

    @AfterClass
    public static void afterClass(){
    	sf.close();
    }

    /**
     * 系统初始化,添加数据
     * 软件部:架构师,软件工程师,程序员
     * 财务部:会计
     * 人事部:无数据
     */
    @Test
    public void testInit(){
    	Session session = sf.openSession() ;
    	Transaction tx = session.beginTransaction() ;

    	Dept d1 = new Dept() ;
    	d1.setName("软件部");
    	Dept d2 = new Dept() ;
    	d2.setName("财务部");
    	Dept d3 = new Dept() ;
    	d3.setName("人事部");

    	Position p1 = new Position() ;
    	p1.setName("架构师");
    	p1.setDept(d1);
    	Position p2 = new Position() ;
    	p2.setName("软件工程师");
    	p2.setDept(d1);
    	Position p3 = new Position() ;
    	p3.setName("程序员");
    	p3.setDept(d1);
    	Position p4 = new Position() ;
    	p4.setName("会计");
        p4.setDept(d2);

        session.save(d1) ;
        session.save(d2) ;
        session.save(d3) ;

        session.save(p1) ;
        session.save(p2) ;
        session.save(p3) ;
        session.save(p4) ;

    	tx.commit();
    	session.close() ;
    }

    /**
     * 我们尝试删除有数据的软件部
     */
    @Test
    public void testDelDept1(){
    	Session session = sf.openSession() ;
    	Transaction tx = session.beginTransaction() ;

    	Dept dept = (Dept)session.get(Dept.class, 1) ;

    	session.delete(dept);

    	tx.commit();
    	session.close() ;
    }

    /**
     * 测试只删除职位(程序员)不删除部门
     */
    @Test
    public void testDelDept2(){
    	Session session = sf.openSession() ;
    	Transaction tx = session.beginTransaction() ;

    	Position position = (Position)session.get(Position.class, 3) ;//程序员ID为3

    	session.delete(position);

    	tx.commit();
    	session.close() ;
    }

}

测试第一个方法,看到绿条,控制台输出:

Hibernate: select max(dept_id) from t_dept
Hibernate: select max(position_id) from t_position
Hibernate: insert into t_dept (dept_name, dept_id) values (?, ?)
Hibernate: insert into t_dept (dept_name, dept_id) values (?, ?)
Hibernate: insert into t_dept (dept_name, dept_id) values (?, ?)
Hibernate: insert into t_position (dept_id, position_name, position_id) values (?, ?, ?)
Hibernate: insert into t_position (dept_id, position_name, position_id) values (?, ?, ?)
Hibernate: insert into t_position (dept_id, position_name, position_id) values (?, ?, ?)
Hibernate: insert into t_position (dept_id, position_name, position_id) values (?, ?, ?)

Mysql生成的表:

 

测试testDelDept1()方法,看到了一个恶心的红条,并且报错了,控制台输出和Junit如下所示:

Hibernate: select dept0_.dept_id as dept1_0_0_, dept0_.dept_name as dept2_0_0_ from t_dept dept0_ where dept0_.dept_id=?
Hibernate: delete from t_dept where dept_id=?

测试testDelDept2()方法同样如此,

Hibernate: select position0_.position_id as position1_1_0_, position0_.dept_id as dept3_1_0_, position0_.position_name as position2_1_0_ from t_position position0_ where position0_.position_id=?
Hibernate: select dept0_.dept_id as dept1_0_0_, dept0_.dept_name as dept2_0_0_ from t_dept dept0_ where dept0_.dept_id=?
Hibernate: delete from t_position where position_id=?
Hibernate: delete from t_dept where dept_id=?

当我把Position.java里面的:

@ManyToOne(targetEntity = Dept.class, fetch = FetchType.LAZY, cascade = { CascadeType.ALL })

改为:

@ManyToOne(targetEntity = Dept.class, fetch = FetchType.LAZY)

时,没有报错,可以成功删除执行了下面语句。

Hibernate: select position0_.position_id as position1_1_0_, position0_.dept_id as dept3_1_0_, position0_.position_name as position2_1_0_ from t_position position0_ where position0_.position_id=?
Hibernate: delete from t_position where position_id=?

从上面我们可以猜测,cascade配置在哪一方配置,那么那个实体类进行操作时,会执行级联的更新或者是删除。

为了解决这个问题,我上网查了很多资料,最后尝试了一个办法,那就是使用双向多对一来配置。

这样我们就需要改一下Dept.java类了:

package org.jian.domain;

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

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;

@Entity
@Table(name = "t_dept")
public class Dept {
    private int id;
    private String name;
    private Set<Position> positions = new HashSet<Position>() ;

    @Id
    @GenericGenerator(name = "generator", strategy = "increment")
    @GeneratedValue(generator = "generator")
    @Column(name="dept_id")
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Column(name="dept_name")
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }

    @OneToMany(mappedBy = "dept", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    public Set<Position> getPositions() {
        return positions;
    }

    public void setPositions(Set<Position> positions) {
        this.positions = positions;
    }

    
}

测试类改一下初始化的代码:

 @Test
    public void testInit(){
    	Session session = sf.openSession() ;
    	Transaction tx = session.beginTransaction() ;

    	Dept d1 = new Dept() ;
    	d1.setName("软件部");
    	Dept d2 = new Dept() ;
    	d2.setName("财务部");
    	Dept d3 = new Dept() ;
    	d3.setName("人事部");

    	Position p1 = new Position() ;
    	p1.setName("架构师");
    	p1.setDept(d1);
    	Position p2 = new Position() ;
    	p2.setName("软件工程师");
    	p2.setDept(d1);
    	Position p3 = new Position() ;
    	p3.setName("程序员");
    	p3.setDept(d1);
    	Position p4 = new Position() ;
    	p4.setName("会计");
        p4.setDept(d2);

        d1.getPositions().add(p1) ;
        d1.getPositions().add(p2) ;
        d1.getPositions().add(p3) ;
        d2.getPositions().add(p4) ;

        session.save(d1) ;
        session.save(d2) ;
        session.save(d3) ;

        session.save(p1) ;
        session.save(p2) ;
        session.save(p3) ;
        session.save(p4) ;

    	tx.commit();
    	session.close() ;
    }

测试这个方法,控制台输出如下:

Hibernate: select max(dept_id) from t_dept
Hibernate: select max(position_id) from t_position
Hibernate: insert into t_dept (dept_name, dept_id) values (?, ?)
Hibernate: insert into t_position (dept_id, position_name, position_id) values (?, ?, ?)
Hibernate: insert into t_position (dept_id, position_name, position_id) values (?, ?, ?)
Hibernate: insert into t_position (dept_id, position_name, position_id) values (?, ?, ?)
Hibernate: insert into t_dept (dept_name, dept_id) values (?, ?)
Hibernate: insert into t_position (dept_id, position_name, position_id) values (?, ?, ?)
Hibernate: insert into t_dept (dept_name, dept_id) values (?, ?)

执行testDelDept1()方法,看到了绿条

Hibernate: select dept0_.dept_id as dept1_0_0_, dept0_.dept_name as dept2_0_0_ from t_dept dept0_ where dept0_.dept_id=?
Hibernate: select positions0_.dept_id as dept3_0_1_, positions0_.position_id as position1_1_, positions0_.position_id as position1_1_0_, positions0_.dept_id as dept3_1_0_, positions0_.position_name as position2_1_0_ from t_position positions0_ where positions0_.dept_id=?
Hibernate: delete from t_position where position_id=?
Hibernate: delete from t_position where position_id=?
Hibernate: delete from t_position where position_id=?
Hibernate: delete from t_dept where dept_id=?

在“一”的一方成功实现了级联删除。

重新生成表

测试testDelDept2()方法,看到了绿条,控制台输出:

Hibernate: select position0_.position_id as position1_1_0_, position0_.dept_id as dept3_1_0_, position0_.position_name as position2_1_0_ from t_position position0_ where position0_.position_id=?
Hibernate: delete from t_position where position_id=?

~综:

1,在一对多(多对一)关系中,如果某个实体类配置了cascade属性(除了设置为‘‘none"),则这个实体类将会执行级联操作。

2,如果想实现在“一”删除后,“多”的数据删除,则必须配置一对多关系。由于需求要求当查询职位时,同时返回部门,所以配置了多对一的关系。综合起来,就是多对一(一对多)双向关联。

Hibernate单向多对一级联删除引发的问题

时间: 2024-10-12 10:42:07

Hibernate单向多对一级联删除引发的问题的相关文章

Hibernate单向多对多

最近做一个OA系统,用到了Hibernate框架,我发现,权限和角色的关系是一种多对多的关系,一个权限可以分配给多个角色,一个角色拥有多个权限. 多对多关系有两种,一种是单向的,一种是多向的.对于这个问题,曾经让我很犯难.单纯在语言上理解,会比较复杂,而从代码上理解,可能就会明白了. 下面模拟为角色授权的过程: 1,Hibernate使用Annotation 2,使用Junit进行测试. 3,使用Mysql作为后台数据库. 4,Hibernate不使用自动建表,也不采用反向工程. 过程 : 1,

再谈Hibernate级联删除——JPA下的Hibernate实现一对多级联删除CascadeType.DELETE_ORPHAN

声明: 1.本文系原创,非抄袭或转载过来的. 2.本文论点都亲手做过实验论证. 3.本文所讲的Hibernate配置都基于注解的方式,hbm语法未提供. 非常多人对持久层概念搞不清JPA.Hibernate.EJB3.0的关系,这里做一下简单的说明:JPA是一个持久层设计接口,EJB3.0和Hibernate是详细的实现类,EJB3.0和Hibernate的功能近似相等的(Hibernate没有Session Bean,Spring MVC3的SessionAttribute跟Session B

Hibernate单向“多对一”关联

1. 基于外键关联的单向"多对一"关联是最常见的单向关联其中指定many-to-one的unique="true",为单向"一对一",不指定就是单向"多对一" <class name="Person">    <id name="id" column="personId"><generator class="native&quo

hibernate单向一对多级联操作

主类  User     单方 从类  UserIp  多方要求结果:操作USER类,自动添加USERIP并维护关联关系 为了节省篇幅,忽略了get/set方法 请自行添加 User类代码: public class User { /**用户的ID*/    private long id; /**登录用户名*/    private String username;        /**登录密码*/    private String password; /**IP集合*/    privat

Hibernate单向多对一映射关系(1)

单向 n-1 单向 n-1 关联只需从 n 的一端可以访问 1 的一端 域模型: 从 Order 到 Customer 的多对一单向关联需要在Order 类中定义一个 Customer 属性, 而在 Customer 类中无需定义存放 Order 对象的集合属性 关系数据模型:ORDERS 表中的 CUSTOMER_ID 参照 CUSTOMER 表的主键        Order.hbm.xml <many-to-one name="customer" class="C

Hibernate多对多级联操作

表与表之间关系回顾(重点) 2 多对多 (1)订单和商品关系,一个订单里面有多个商品,一个商品属于多个订单 (2)用户和角色多对多关系 - 用户: 小王.小马.小宋 - 角色:总经理.秘书.司机.保安 ** 比如小王 可以 是总经理,可以是司机 ** 比如小宋 可以是司机,可以是秘书,可以保安 ** 比如小马 可以是 秘书,可以是总经理 -          一个用户里面可以有多个角色,一个角色里面可以有多个用户 (3)多对多建表:创建第三张表维护关系 Hibernate多对多操作 多对多映射配

关联映射 ---- Hibernate之多对多关系

叙:上一章详细的记录了关联映射中的"一对多|多对一"关系.级联操作.关系的维护等知识点,本章节轻风学习记录的是级联关系中的"多对多"关系: Hibernate的"多对多"级联关系 1. 介绍 在生活中很多关系都是多对多的,比如一个人在公司是技术部的同时也是营销部的(只是个例子),所以,多对对关系是很普遍的,一个对象有多个角色,而一个角色又可以有多个对象,因此最正确的做法是在对象与角色之间创建一个新的表,用来保存对象和角色的主键,方便调用查看相应的

hibernate级联删除

一对多的双向关联:user对应多个order user.xml: <class name="com.examp.ShoppingOnline.User"             table="user"            discriminator-value="C">                       <id name="id">             <generator cl

Hibernate 单向/双向 多对多

Hibernate的多对多从单向和双向来分就是单向多对多和双向多对多两种. Hibernate的双向多对多 先来说一下什么是多对多的关系,举个例子,老师和学生,老师有语文老师,数学老师,英语老师等等,学生可以是1班的学生也可以是2班的学生,对于每个学生而言,他有多个老师给他讲课,而对于每一个老师而言,他要授课的学生也有很多,像这样的情况就可以描述成多对多了.即两个表之间,每一个表中的记录都对应另一个表的部分或全部记录的集合,这种情况就是多对多关系,而单向多对多与双向多对多的不同在于单向只是一方的