现在演示“多:多,双向导航”。由于实际项目中,首先进行数据库设计,所以,从数据库设计推出POJO的设计是很必要的.
student<->teacher
数据库表:
设计思路:
1.2个POJO类,Teacher对应于t_teacher表。Student对应于t_student表。
2.确定导航要求,为双向导航,使用ManyToMany,一端使用mappedBy。2端都是用cascadeType.ALL
3.POJO类的隐式字段自动映射成表中同名字段,所以,方便起见,类的属性与表中普通字段名完全一致。
4.在getId上设置@Id,@GeneratedValue
5.在一端使用了ManyToMany的后面设置@JoinTable“外键表”的名字,字段名。
POJO类
Student类:
@Entity @Table(name="t_student")//设置映射的表名 public class Student { private int id; private String name;//隐式映射为同名字段 private Set<Teacher> teachers = new HashSet<Teacher>(); @Id @GeneratedValue(strategy=GenerationType.AUTO)//自增 public int getId() { return id; } public String getName() { return name; } @ManyToMany(cascade={CascadeType.ALL})//增删改级联 @JoinTable(name = "t_student_teacher", joinColumns = { @JoinColumn(name = "student_id") }, inverseJoinColumns = { @JoinColumn(name = "teacher_id") })//映射的连接表名和字段名 public Set<Teacher> getTeachers() { return teachers; } public void setId(int id) { this.id = id; } public void setName(String name) { this.name = name; } public void setTeachers(Set<Teacher> teachers) { this.teachers = teachers; } }
Teacher类:
@Entity @Table(name="t_teacher")//映射的表名 public class Teacher { private int id; private String name;//隐式映射同名字段名 private Set<Student> students = new HashSet<Student>(); @Id @GeneratedValue(strategy=GenerationType.AUTO)//自增 public int getId() { return id; } public String getName() { return name; } @ManyToMany(mappedBy="teachers",cascade={CascadeType.ALL})//mappedBy防止冗余。增删改级联 public Set<Student> getStudents() { return students; } public void setId(int id) { this.id = id; } public void setName(String name) { this.name = name; } public void setStudents(Set<Student> students) { this.students = students; } }
测试
save:
Student s1 = new Student(); s1.setName("s1"); Student s2 = new Student(); s2.setName("s2"); Teacher t1 = new Teacher(); t1.setName("t1"); Teacher t2 = new Teacher(); t2.setName("t2"); s1.getTeachers().add(t1); s1.getTeachers().add(t2);// save s1的时候可以save t1,t2 s2.getTeachers().add(t1); s2.getTeachers().add(t2);// t1,t2被保存过,hibernate会忽略这次保存,但是会插入到“连接表”中 Session session = sessionFactory.getCurrentSession(); session.beginTransaction(); session.save(s1);// 插入s1,既可以插入t1和t2 session.save(s2);// 插入s2,最后向中间表插入4条记录 session.getTransaction().commit();
删除
@Test public void testDel() { // 删除s1,以及“连接表"中拥有s1的记录 Session session = sessionFactory.getCurrentSession(); session.beginTransaction(); Student s1 = (Student) session.load(Student.class, 10);// load一下 s1.setTeachers(null);//将关联打破,不去级联删除Teacher中的记录。 session.delete(s1); session.getTransaction().commit(); }
修改
@Test public void testUpadte() { // 让连接表中,12只有11号一个老师教 Session session = sessionFactory.getCurrentSession(); session.beginTransaction(); Student s1 = (Student) session.load(Student.class, 12);// load一下 Teacher t2 = (Teacher)session.load(Teacher.class, 11); s1.getTeachers().clear(); s1.getTeachers().add(t2); session.getTransaction().commit(); }
查询
@Test public void testRead() { //读出学生,以及教他的所有老师 Session session = sessionFactory.getCurrentSession(); session.beginTransaction(); Student s1 = (Student) session.load(Student.class, 12);// load一下 Set<Teacher> teachers = s1.getTeachers(); System.out.println("学生姓名:"+s1.getName()); for(Teacher t:teachers){ System.out.println("老师姓名:"+t.getName()); } session.getTransaction().commit(); }