多对多关系相比其他其中关联关系,显得稍微复杂了一点点,这个复杂度主要体现在对这种关联关系的理解上。和其他关联关系不同的是这种关联多出来了一张中间表,操作上多了些许复杂,来随便看下吧
1 实体的定义
Student表:
package org.lxh.info;
import java.util.*;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
@Entity
public class Student {
private Integer id;
private String name;
private Set<Teacher> teachers;
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(length = 50)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToMany(cascade=CascadeType.REFRESH)
@JoinTable(name="student_teacher",inverseJoinColumns=@JoinColumn(name="teacherId"),joinColumns=@JoinColumn(name="stuId"))
public Set<Teacher> getTeachers() {
return teachers;
}
public void setTeachers(Set<Teacher> teachers) {
this.teachers = teachers;
}
}
@ManyToMany表示多对多关联,对于这种关联极少数情况会使用级联删除,我这里设置的是级联刷新;因为有中间表的存在这里使用@JoinTable来设置关联表后面的name配置的是关联表的名称,inverseJoinColumn配置的是关系被维护一方主键对应的中间表字段,joinColumn配置的是关系维护方主键对应的中间表字段。这里是最复杂的地方
Teacher表:
package org.lxh.info;
import java.util.*;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
@Entity
public class Teacher {
private Integer id;
private String name;
private Set<Student> students;
@Id @GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(length=50)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToMany(cascade=CascadeType.REFRESH,mappedBy="teachers")
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}
到这里实体就定义完了,要注意的地方就是只有关系维护的一方才能更新中间表里的外键记录。如果反过来则会报错
2 多对多数据保存
/**
* 双向多对多保存
*/
@org.junit.Test
public void testMany2ManyInsert() {
EntityManager em=null;
EntityTransaction tx=null;
try{
em=JpaUtil.getEntityManager();
tx=em.getTransaction();
tx.begin();
Student s=new Student();
s.setName("张小华");
Student s2=new Student();
s2.setName("陈小明");
Set<Student> students=new HashSet<Student>();
students.add(s);
students.add(s2);
Teacher t=new Teacher();
t.setName("李老师");
t.setStudents(students);
Teacher t2=new Teacher();
t2.setName("刘老师");
t2.setStudents(students);
Set<Teacher> teachers=new HashSet<Teacher>();
teachers.add(t);
teachers.add(t2);
s.setTeachers(teachers);
s2.setTeachers(teachers);
em.persist(s);
em.persist(s2);
em.persist(t);
em.persist(t2);
tx.commit();
}catch(Exception e){
e.printStackTrace();
}finally{
if(em!=null){
em.close();
}
}
}
保存操作是比较简单的,但是如果要删除或解除关联关系,就稍显复杂了,来看这段代码
@org.junit.Test
public void testMany2ManyDelete() {
EntityManager em=null;
EntityTransaction tx=null;
try{
em=JpaUtil.getEntityManager();
tx=em.getTransaction();
tx.begin();
Student s=em.find(Student.class, 1);
Student s2=em.find(Student.class, 2);
Teacher t=em.find(Teacher.class, 2);
//先解除关联关系
s.getTeachers().remove(t);
s2.getTeachers().remove(t);
//解除关联关系后才能通过关系被维护端删除数据
em.remove(t);
tx.commit();
}catch(Exception e){
e.printStackTrace();
}finally{
if(em!=null){
em.close();
}
}
}
最后总结一下使用关联关系的要点:分清楚关系维护端和关系被维护端、合理的使用注解、级联的设置根据具体情况指定。