Hibernate多对多删除问题的解决
关键字: hibernate,多对多,删除
Hibernate多对多的例子不少,但仔细一看,大多数都是保存的,删除谈的少,但问题还不少,因此有必须简单测试一下,以下我们来个简单的多对多关系建立
老师Teacher 与 课程Course 是一个多对多的关系,Pojo与XMl配置如下。
Pojo
Java代码
1. /**
2. * Course Entity
3. * see table: tbl_course
4. */
5. package com.leo.domain;
6.
7. import java.util.HashSet;
8. import java.util.Set;
9.
10. /**
11. * @author superleo
12. *
13. */
14. public class Course {
15.
16. private String id;
17.
18. private String name;
19.
20. private Set<Teacher> teachers = new HashSet<Teacher>();
21.
22. public String getId() {
23. return id;
24. }
25.
26. public void setId(String id) {
27. this.id = id;
28. }
29.
30. public String getName() {
31. return name;
32. }
33.
34. public void setName(String name) {
35. this.name = name;
36. }
37.
38. public Set<Teacher> getTeachers() {
39. return teachers;
40. }
41.
42. public void setTeachers(Set<Teacher> teachers) {
43. this.teachers = teachers;
44. }
45.
46. }
Java代码
1. /**
2. * Teacher Entity
3. * see table: tbl_teacher
4. */
5. package com.leo.domain;
6.
7. import java.util.HashSet;
8. import java.util.Set;
9.
10. /**
11. * @author superleo
12. *
13. */
14. public class Teacher {
15.
16. private String id;
17.
18. private String name;
19.
20. private Set<Course> courses = new HashSet<Course>();
21.
22. public String getId() {
23. return id;
24. }
25.
26. public void setId(String id) {
27. this.id = id;
28. }
29.
30. public String getName() {
31. return name;
32. }
33.
34. public void setName(String name) {
35. this.name = name;
36. }
37.
38. public Set<Course> getCourses() {
39. return courses;
40. }
41.
42. public void setCourses(Set<Course> courses) {
43. this.courses = courses;
44. }
45.
46. }
配置文件也非常简单:
Xml代码
1. <?xml version="1.0"?>
2. <!DOCTYPE hibernate-mapping PUBLIC
3. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
4. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
5.
6. <hibernate-mapping>
7. <class name="com.leo.domain.Course" table="tbl_course"
8. batch-size="100" dynamic-insert="true" dynamic-update="true">
9. <id name="id" column="id">
10. <generator class="uuid" />
11. </id>
12. <property name="name" column="name" type="string" />
13.
14. <set access="property" lazy="true" inverse="false"
15. cascade="save-update" name="teachers" batch-size="10" fetch="select"
16. table="tbl_teacher_course">
17. <key column="fk_course_id" />
18. <many-to-many class="com.leo.domain.Teacher"
19. column="fk_teacher_id" />
20. </set>
21.
22. </class>
23. </hibernate-mapping>
Xml代码
1. <?xml version="1.0"?>
2. <!DOCTYPE hibernate-mapping PUBLIC
3. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
4. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
5.
6. <hibernate-mapping>
7. <class name="com.leo.domain.Teacher" table="tbl_teacher"
8. batch-size="100" dynamic-insert="true" dynamic-update="true">
9. <id name="id" column="id">
10. <generator class="uuid" />
11. </id>
12. <property name="name" column="name" type="string" />
13.
14. <set access="property" lazy="true" inverse="true"
15. cascade="save-update" name="courses" batch-size="10" fetch="select"
16. table="tbl_teacher_course">
17. <key column="fk_teacher_id" />
18. <many-to-many class="com.leo.domain.Course"
19. column="fk_course_id" />
20. </set>
21.
22. </class>
23. </hibernate-mapping>
先往数据库里插入一些记录:
Java代码
1. public void testSave() {
2. Session session = HibernateSessionFactory.getSession();
3. session.beginTransaction();
4.
5. // create course
6. Course c1 = new Course();
7. Course c2 = new Course();
8. c1.setName("C");
9. c2.setName("Java");
10.
11. // create teacher
12. Teacher t1 = new Teacher();
13. Teacher t2 = new Teacher();
14. t1.setName("Leo");
15. t2.setName("Rose");
16.
17. // create relationship
18. c1.getTeachers().add(t1);
19. c1.getTeachers().add(t2);
20. t1.getCourses().add(c1);
21. t2.getCourses().add(c1);
22.
23. /* 因为主控方级联设置为save-update,如果设置为none,则下面被注释的代码需要开启,否则会报错 */
24. //session.save(t1);
25. //session.save(t2);
26. session.save(c1);
27.
28. session.getTransaction().commit();
29. session.close();
30. }
下面是测试的一些结果:
1. 如果cascade不管主控方设置还是被控方设置成 all, delete等与delete级联删除有关即可,两端以及中间表的记录都会被删除,通常这样的需要是很少的,因此,如果你要这样的情况,只要简单设置成all, delete就可以轻松的将关系以及两端的记录删除的干干净净。
2. 只想删除某一端的记录以及中间的表的关联信息。 这种需求通常是很常见的。这个时候cascade的设置是除与delete有关的任何级联约束。以下是删除心得:
Java代码
1. /**
2. * 多对多 主控方删除(可以删除中间表记录)
3. */
4. public void testDelete() {
5. String id = "402881ee175f04be01175f04c05d0001";
6. Session session = HibernateSessionFactory.getSession();
7. session.beginTransaction();
8. Course c1 = (Course) session.get(Course.class, id);
9. session.delete(c1);
10. session.getTransaction().commit();
11. session.close();
12. }
Java代码
1. /**
2. * 多对多 被控方删除(无法删除中间表记录)
3. */
4. public void testDeleteByInverse() {
5. String id = "402881ee175a2e7c01175a2e7ead0003";
6. Session session = HibernateSessionFactory.getSession();
7. session.beginTransaction();
8. Teacher t1 = (Teacher) session.get(Teacher.class, id);
9. session.delete(t1);
10. session.getTransaction().commit();
11. session.close();
12. }
Java代码
1. /**
2. * 多对多 被控方删除(可以删除中间表记录)
3. */
4. public void testDeleteByInverse2() {
5. String id = "402881ee175f04be01175f04c06c0002";
6. Session session = HibernateSessionFactory.getSession();
7. session.beginTransaction();
8.
9. Teacher t1 = (Teacher) session.get(Teacher.class, id);
10.
11. Set<Course> cs = t1.getCourses();
12. for (Course c : cs) {
13. c.getTeachers().remove(t1);
14. }
15.
16. session.delete(t1);
17. session.getTransaction().commit();
18. session.close();
19. }
完成了。 但如果是Spring+Hiberante下多对多删除,可能会报一个错误,目前的解决办法是把两端的cascade都设置成none. 初步断定可能与事务有关,如果有人遇到了,并知道为什么,希望能留言,先谢谢大家了。
注:三个表的表结构
1. tbl_course.sql
create table "SCOTT"."TBL_COURSE"(
"ID" VARCHAR2(80) not null,
"NAME" VARCHAR2(20) not null,
constraint "SYS_C005315" primary key ("ID")
);
2. tbl_teacher.sql
create table "SCOTT"."TBL_TEACHER"(
"ID" VARCHAR2(80) not null,
"NAME" VARCHAR2(20) not null,
constraint "SYS_C005313" primary key ("ID")
);
3.tbl_teacher_course.sql
create table "SCOTT"."TBL_TEACHER_COURSE"(
"FK_TEACHER_ID" VARCHAR2(80),
"FK_COURSE_ID" VARCHAR2(90)
);只删除中间表,可以通过以下代码。
/**
* 多对多 通过主控方删除中间表(其余记录都不变)
*/
public void testDeleteByInverse3() {
String id = "402881ee1782dad9011782dadb310001";
Session session = HibernateSessionFactory.getSession();
session.beginTransaction();
Course c1 = (Course) session.get(Course.class, id);
c1.setTeachers(null);
session.getTransaction().commit();
session.close();
}
/**
* 多对多 通过被控方删除中间表(其余记录都不变)
*/
public void testDeleteByInverse4() {
String id = "402881ee1782dbd4011782dbd64a0002";
Session session = HibernateSessionFactory.getSession();
session.beginTransaction();
Teacher t1 = (Teacher) session.get(Teacher.class, id);
Set<Course> cs = t1.getCourses();
for (Course c : cs) {
c.getTeachers().remove(t1);
}
session.getTransaction().commit();
session.close();
}
标签:Hibernate,String,删除,Teacher,id,Course,session,解决,public
From: https://blog.51cto.com/u_16065168/6442948