1. 多对多pojo及映射信息
1)表结构分析
多对多需要有一张中间表,只有两列且均引用外键,分别就是两张主体表的主键
2)pojo
public class Student {
private Long id;
private String name;
private Set<Teacher> teachers = new HashSet<Teacher>();<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">}</span>
public class Teacher {
private Long id;
private String name;
private Set<Student> students = new HashSet<Student>();
..........
}
3) 映射文件
<class name="cn.com.cpf.pojo.Student" table="t_student" >
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="teachers" table="teacher_student">
<key column="studentId"/>
<many-to-many class="cn.com.cpf.pojo.Teacher" column="teacherId"/>
</set>
</class>
<class name="cn.com.cpf.pojo.Teacher" table="t_teacher" >
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="students" table="teacher_student">
<key column="teacherId"/>
<many-to-many class="cn.com.cpf.pojo.Student" column="studentId"/>
</set>
</class>
理解:其实也就是Set映射,key为外键,为关联到本类的主键列;因为Set中是类,所以使用class
4)结果
t_student表
t_teacher表
teacher_student表
2. save操作
1)多对多双方都未配置inverse=true,且代码中双方均保存了对方对象
service中代码:
SessionFactory factory = null;
Session session = null;
try
{
factory = new Configuration().configure().buildSessionFactory();
session = factory.openSession();
Transaction tx = session.beginTransaction();
Student student1 = new Student();
student1.setName("xny");
Student student2 = new Student();
student2.setName("zq");
Teacher teacher1 = new Teacher();
teacher1.setName("ma");
Teacher teacher2 = new Teacher();
teacher2.setName("shi");
student1.getTeachers().add(teacher1);
student1.getTeachers().add(teacher2);
student2.getTeachers().add(teacher1);
student2.getTeachers().add(teacher2);
teacher1.getStudents().add(student1);
teacher1.getStudents().add(student2);
teacher2.getStudents().add(student1);
teacher2.getStudents().add(student2);
session.save(student1);
session.save(student2);
session.save(teacher1);
session.save(teacher2);
tx.commit();
}
映射信息:
<set name="teachers" table="teacher_student">
<key column="studentId"/>
<many-to-many class="cn.com.cpf.pojo.Teacher" column="teacherId"/>
</set>
<set name="students" table="teacher_student">
<key column="teacherId"/>
<many-to-many class="cn.com.cpf.pojo.Student" column="studentId"/>
</set>
结果:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '1-1' for key 'PRIMARY'
原因:在多对多关系中,中间表使用的是联合主键,而在映射文件中双方都维护多对多关系(也就是在插入的时候都将值插入中间表),这样就相当于同一个值在中间表中插入两次,所以就会报主键重复错误——解决方法为只有一端维护关系
2)多对多双方只有一方维护关系
映射文件:
<set name="students" table="teacher_student" inverse="true">
<key column="teacherId"/>
<many-to-many class="cn.com.cpf.pojo.Student" column="studentId"/>
</set>
Hibernate: insert into t_student (name) values (?)
Hibernate: insert into t_student (name) values (?)
Hibernate: insert into t_teacher (name) values (?)
Hibernate: insert into t_teacher (name) values (?)
Hibernate: insert into teacher_student (studentId, teacherId) values (?, ?)
Hibernate: insert into teacher_student (studentId, teacherId) values (?, ?)
Hibernate: insert into teacher_student (studentId, teacherId) values (?, ?)
Hibernate: insert into teacher_student (studentId, teacherId) values (?, ?)
t_student:
t_teacher
teacher_student
这样已经不能称之为多对多,因为这个关系双方均不维护,所以根本就不会创建中间表
3. get操作
Teacher teacher = (Teacher) session.get(Teacher.class, 1l);
System.out.println(teacher.getName());
System.out.println(teacher.getStudents());
Student student = (Student) session.get(Student.class, 1l);
System.out.println(student.getName());
System.out.println(student.getTeachers());
结果为:
Hibernate: select teacher0_.id as id1_4_0_, teacher0_.name as name2_4_0_ from t_teacher teacher0_ where teacher0_.id=?
ma
Hibernate: select students0_.teacherId as teacherI2_4_0_, students0_.studentId as studentI1_7_0_, student1_.id as id1_3_1_, student1_.name as name2_3_1_ from teacher_student students0_ inner join t_student student1_ on students0_.studentId=student1_.id where students0_.teacherId=?
[cn.com.cpf.pojo.Student@75f2edd2, cn.com.cpf.pojo.Student@1fdbb27d]
xny
Hibernate: select teachers0_.studentId as studentI1_3_0_, teachers0_.teacherId as teacherI2_7_0_, teacher1_.id as id1_4_1_, teacher1_.name as name2_4_1_ from teacher_student teachers0_ inner join t_teacher teacher1_ on teachers0_.teacherId=teacher1_.id where teachers0_.studentId=?
[cn.com.cpf.pojo.Teacher@2a509df8, cn.com.cpf.pojo.Teacher@391da0]
4. 解除关系
1)由inverse=true的一端来解除
<set name="students" table="teacher_student" inverse="true">
<key column="teacherId"/>
<many-to-many class="cn.com.cpf.pojo.Student" column="studentId"/>
</set>
Teacher teacher = (Teacher) session.get(Teacher.class, 1l);
teacher.getStudents().clear();
结果为:
Hibernate: select teacher0_.id as id1_4_0_, teacher0_.name as name2_4_0_ from t_teacher teacher0_ where teacher0_.id=?
因为没有执行delete语句(所谓解除关系,就是删除中间表中的相关数据),所以显然没有解除
原因:因为Teacher端的inverse属性为true,不再执行中间表的相关操作了,所以肯定不能用这一端来解除
2)由inverse=false的一端来解除
<set name="teachers" table="teacher_student">
<key column="studentId"/>
<many-to-many class="cn.com.cpf.pojo.Teacher" column="teacherId"/>
</set>
Student student = (Student) session.get(Student.class, 1l);
student.getTeachers().clear();
结果:
Hibernate: select student0_.id as id1_3_0_, student0_.name as name2_3_0_ from t_student student0_ where student0_.id=?
Hibernate: select teachers0_.studentId as studentI1_3_0_, teachers0_.teacherId as teacherI2_7_0_, teacher1_.id as id1_4_1_, teacher1_.name as name2_4_1_ from teacher_student teachers0_ inner join t_teacher teacher1_ on teachers0_.teacherId=teacher1_.id where teachers0_.studentId=?
Hibernate: delete from teacher_student where studentId=?
5. 删除
1) 无关联对象:直接删除即可
2) 有关联对象,且inverse=true
Teacher teacher = (Teacher) session.get(Teacher.class, 1l);
session.delete(teacher);
结果:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`teacher_student`, CONSTRAINT `FK_ssifa0mqor3f0e70gmvue7lc6` FOREIGN KEY (`teacherId`) REFERENCES `t_teacher` (`id`))
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
愿意:因为根本不能操作中间表,所以肯定会报外键异常
3) 有关联对象,且inverse=false
Student student = (Student) session.get(Student.class, 2l);
session.delete(student);
Hibernate: select student0_.id as id1_3_0_, student0_.name as name2_3_0_ from t_student student0_ where student0_.id=?
Hibernate: delete from teacher_student where studentId=?
Hibernate: delete from t_student where id=?