欢迎关注我的Github Pages: http://chendu.github.io/
Hibernate多对多(many-to-many):在操作和性能方面都不太理想,所以多对多的关系使用的比较少,实际使用最好转换成一对多的对象模型,实际上Hibernate可以帮我们创建中间关联表,转换成两个一对多的关系.
比如老师和学生是比较常见的多对多关系,我们可以创建一个中间表,用中间表去记录老师和学生之间多对多的关系.
Teacher.java
@Entity
@Table(name = "TB_TEACHER")
public class Teacher {
private int teacherId;
private String teacherName;
private Set<Student> students = new HashSet<Student>();
public Teacher(){}
public Teacher(String teacherName){
this.teacherName = teacherName;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "TEACHER_ID", unique = true, nullable = false)
public int getTeacherId() {
return teacherId;
}
public void setTeacherId(int teacherId) {
this.teacherId = teacherId;
}
@Column(name = "TEACHER_NAME")
public String getTeacherName() {
return teacherName;
}
public void setTeacherName(String teacherName) {
this.teacherName = teacherName;
}
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinTable(name = "TB_TEACHER_STUDENT",
joinColumns = {
@JoinColumn(name = "TEACHER_ID", nullable = false, updatable = false) },
inverseJoinColumns = {
@JoinColumn(name = "STUDENT_ID", nullable = false, updatable = false) })
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}
Student.java
@Entity
@Table(name = "TB_STUDENT")
public class Student {
private int studentId;
private String studentName;
private Set<Teacher> teachers = new HashSet<Teacher>();
public Student(){}
public Student(String studentName){
this.studentName = studentName;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "STUDENT_ID", unique = true, nullable = false)
public int getStudentId() {
return studentId;
}
public void setStudentId(int studentId) {
this.studentId = studentId;
}
@Column(name = "STUDENT_NAME")
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
@ManyToMany(fetch = FetchType.LAZY, mappedBy = "students")
public Set<Teacher> getTeachers() {
return teachers;
}
public void setTeachers(Set<Teacher> teachers) {
this.teachers = teachers;
}
}
通过设置Hibernate自动生成代码
hibernate.show_sql = true
hibernate.format_sql = true
hibernate.hbm2ddl.auto = create
自动生成的DDL SQL语句
CREATE TABLE `tb_teacher` (
`TEACHER_ID` INT(11) NOT NULL AUTO_INCREMENT,
`TEACHER_NAME` VARCHAR(255) NULL DEFAULT NULL,
PRIMARY KEY (`TEACHER_ID`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
CREATE TABLE `tb_student` (
`STUDENT_ID` INT(11) NOT NULL AUTO_INCREMENT,
`STUDENT_NAME` VARCHAR(255) NULL DEFAULT NULL,
PRIMARY KEY (`STUDENT_ID`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
CREATE TABLE `tb_teacher_student` (
`TEACHER_ID` INT(11) NOT NULL,
`STUDENT_ID` INT(11) NOT NULL,
PRIMARY KEY (`TEACHER_ID`, `STUDENT_ID`),
INDEX `FK_9484qoyn1n7mq08lbv4q2wni0` (`STUDENT_ID`),
CONSTRAINT `FK_9484qoyn1n7mq08lbv4q2wni0` FOREIGN KEY (`STUDENT_ID`) REFERENCES `tb_student` (`STUDENT_ID`),
CONSTRAINT `FK_l1jwjq45c5vucjgivby1e41a5` FOREIGN KEY (`TEACHER_ID`) REFERENCES `tb_teacher` (`TEACHER_ID`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
A. 测试插入操作:
Teacher teacher1 = new Teacher("teacher1");
Teacher teacher2 = new Teacher("teacher2");
Student student1 = new Student("student1");
Student student2 = new Student("student2");
student1.getTeachers().add(teacher1);
student1.getTeachers().add(teacher2);
student2.getTeachers().add(teacher1);
session.save(teacher1);
session.save(teacher2);
session.save(student1);
session.save(student2);
用上面的语句执行插入操作,后台console打印出来的SQL:
Hibernate:
insert
into
TB_TEACHER
(TEACHER_NAME)
values
(?)
Hibernate:
insert
into
TB_TEACHER
(TEACHER_NAME)
values
(?)
Hibernate:
insert
into
TB_STUDENT
(STUDENT_NAME)
values
(?)
Hibernate:
insert
into
TB_STUDENT
(STUDENT_NAME)
values
(?)
数据库中数据
TB_STUDENT
STUDENT_ID | STUDENT_NAME |
---|---|
1 | student1 |
2 | student2 |
TB_TEACHER
TEACHER_ID | TEACHER_NAME |
---|---|
1 | teacher1 |
2 | teacher2 |
TB_TEACHER_STUDENT (NULL)
B.测试插入操作:
Teacher teacher1 = new Teacher("teacher1");
Teacher teacher2 = new Teacher("teacher2");
Student student1 = new Student("student1");
Student student2 = new Student("student2");
teacher1.getStudents().add(student1);
teacher1.getStudents().add(student2);
teacher2.getStudents().add(student1);
session.save(teacher1);
session.save(teacher2);
session.save(student1);
session.save(student2);
用上面的语句执行插入操作,后台console打印出来的SQL:
Hibernate:
insert
into
TB_TEACHER
(TEACHER_NAME)
values
(?)
Hibernate:
insert
into
TB_STUDENT
(STUDENT_NAME)
values
(?)
Hibernate:
insert
into
TB_STUDENT
(STUDENT_NAME)
values
(?)
Hibernate:
insert
into
TB_TEACHER
(TEACHER_NAME)
values
(?)
Hibernate:
insert
into
TB_TEACHER_STUDENT
(TEACHER_ID, STUDENT_ID)
values
(?, ?)
Hibernate:
insert
into
TB_TEACHER_STUDENT
(TEACHER_ID, STUDENT_ID)
values
(?, ?)
Hibernate:
insert
into
TB_TEACHER_STUDENT
(TEACHER_ID, STUDENT_ID)
values
(?, ?)
数据库中数据
TB_STUDENT
STUDENT_ID | STUDENT_NAME |
---|---|
1 | student1 |
2 | student2 |
TB_TEACHER
TEACHER_ID | TEACHER_NAME |
---|---|
1 | teacher1 |
2 | teacher2 |
TB_TEACHER_STUDENT
TEACHER_ID | STUDENT_ID |
---|---|
1 | 1 |
1 | 2 |
2 | 1 |
A 和 B操作的唯一区别是
//A
student1.getTeachers().add(teacher1);
student1.getTeachers().add(teacher2);
student2.getTeachers().add(teacher1);
//B
teacher1.getStudents().add(student1);
teacher1.getStudents().add(student2);
teacher2.getStudents().add(student1);
需要注意的是Student.java, @ManyToMany的属性mappedBy = "students"
@Entity
@Table(name = "TB_STUDENT")
public class Student {
...
@ManyToMany(fetch = FetchType.LAZY, mappedBy = "students")
public Set<Teacher> getTeachers() {
return teachers;
}
...
}
当配置了这句话的时候就不可以再配置@JoinTable和@JoinColumn等,同时Teacher就是owning side, Student就是non-owning side,就是Teacher和Student之间的关系是通过Teacher端来维护的.