多对多关系是关系数据库中两个表之间的一种关系,该关系中第一个表中的一个行可以与第二个表中的一个或多个行相关。第二个表中的一个行也可以与第一个表中的一个或多个行相关。
下面将通过教师和学生的关系来演示 OpenJPA 中怎样实现多对多关系映射,在 OpenJPA 中,使用 @ManyToMany 注解来指定多对多关系。
多对多关系的表结构设计和一对多关系表结构是一致的,OpenJPA 中使用的是中间表来维护关系。数据表结构图如下:
上图的中间表用来保存教师和学生关系。
(1)教师表对应的 Teacher 对象,代码如下:
@Data @Entity @Table public class Teacher { @Id @GeneratedValue private int id; @Column private String name; @ManyToMany private List<Student> studentList; }
(2)学生表对应的 Student 对象,代码如下:
@Data @Entity @Table public class Student { @Id @GeneratedValue private int id; @Column private String name; // 放弃多对多关系维护,让 Teacher 维护多对多关系 @ManyToMany(mappedBy = "studentList") private List<Teacher> teacherList; }
上图中,使用 mappedBy 属性放弃 Student 方对关系的维护。如果不进行 mappedBy 配置,则会创建两张关系表,分别有 Student 和 Teacher 进行维护。
(1)教师实体对象,代码如下:
@Data @Entity @Table public class Teacher { @Id @GeneratedValue private int id; @Column private String name; @ManyToMany private List<Student> studentList; }
(2)学生实体对象,代码如下:
@Data @Entity @Table public class Student { @Id @GeneratedValue private int id; @Column private String name; // 放弃多对多关系维护,让 Teacher 维护多对多关系 @ManyToMany(mappedBy = "studentList") private List<Teacher> teacherList; }
(3)客户端代码
import com.alibaba.fastjson.JSONObject; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import javax.persistence.TypedQuery; import java.util.ArrayList; import java.util.List; /** * 双向多对多映射 * @author Administrator 2021-9-10 13:37:37 */ public class Demo { /** 持久化单元名称 */ private static final String NAME = "demo_manytomany"; private static void insertData(EntityManager em) { try { em.getTransaction().begin(); // 教师 Teacher teacher1 = new Teacher(); teacher1.setName("教师1"); Teacher teacher2 = new Teacher(); teacher2.setName("教师2"); List<Teacher> teacherList = new ArrayList<Teacher>(); teacherList.add(teacher1); teacherList.add(teacher2); // 学生 Student student1 = new Student(); student1.setName("学生1"); Student student2 = new Student(); student2.setName("学生2"); List<Student> studentList = new ArrayList<Student>(); studentList.add(student1); studentList.add(student2); teacher1.setStudentList(studentList); teacher2.setStudentList(studentList); student1.setTeacherList(teacherList); student2.setTeacherList(teacherList); // 持久化 em.persist(student1); em.persist(student2); em.persist(teacher1); em.persist(teacher2); em.getTransaction().commit(); } finally { em.close(); } } private static void selectData(EntityManager em) { try { em.getTransaction().begin(); // 查询教师信息 TypedQuery<Teacher> teacherTypedQuery = em.createQuery( "select t from Teacher t", Teacher.class); for(Teacher teacher : teacherTypedQuery.getResultList()) { System.out.println("teacher_id=" + teacher.getId()); System.out.println("teacher_name=" + teacher.getName()); System.out.println("teacher_students=" + JSONObject.toJSONString(teacher.getStudentList())); } // 查询学生信息 TypedQuery<Student> studentTypedQuery = em.createQuery( "select s from Student s", Student.class); for(Student student : studentTypedQuery.getResultList()) { System.out.println("student_id=" + student.getId()); System.out.println("student_name=" + student.getName()); System.out.println("student_teacher=" + JSONObject.toJSONString(student.getTeacherList())); } em.getTransaction().commit(); } finally { em.close(); } } public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory(NAME); // 插入数据 insertData(emf.createEntityManager()); // 查询数据 selectData(emf.createEntityManager()); emf.close(); System.out.println("finished."); } }
执行上面客户端代码后,输出的SQL如下:
-- 创建表格和索引 CREATE TABLE OPENJPA_SEQUENCE_TABLE (ID TINYINT NOT NULL, SEQUENCE_VALUE BIGINT, PRIMARY KEY (ID)) ENGINE = innodb CREATE TABLE Student (id INTEGER NOT NULL, name VARCHAR(255), PRIMARY KEY (id)) ENGINE = innodb CREATE TABLE Teacher (id INTEGER NOT NULL, name VARCHAR(255), PRIMARY KEY (id)) ENGINE = innodb CREATE TABLE Teacher_Student (TEACHERLIST_ID INTEGER, STUDENTLIST_ID INTEGER) ENGINE = innodb CREATE INDEX I_TCHRDNT_ELEMENT ON Teacher_Student (STUDENTLIST_ID) CREATE INDEX I_TCHRDNT_TEACHERLIST_ID ON Teacher_Student (TEACHERLIST_ID) -- 使用序列表生成ID值 SELECT SEQUENCE_VALUE FROM OPENJPA_SEQUENCE_TABLE WHERE ID = ? FOR UPDATE [params=?] INSERT INTO OPENJPA_SEQUENCE_TABLE (ID, SEQUENCE_VALUE) VALUES (?, ?) [params=?, ?] SELECT SEQUENCE_VALUE FROM OPENJPA_SEQUENCE_TABLE WHERE ID = ? FOR UPDATE [params=?] UPDATE OPENJPA_SEQUENCE_TABLE SET SEQUENCE_VALUE = ? WHERE ID = ? AND SEQUENCE_VALUE = ? [params=?, ?, ?] SELECT SEQUENCE_VALUE FROM OPENJPA_SEQUENCE_TABLE WHERE ID = ? FOR UPDATE [params=?] UPDATE OPENJPA_SEQUENCE_TABLE SET SEQUENCE_VALUE = ? WHERE ID = ? AND SEQUENCE_VALUE = ? [params=?, ?, ?] -- 插入学生信息 INSERT INTO Student (id, name) VALUES (?, ?) [params=?, ?] INSERT INTO Student (id, name) VALUES (?, ?) [params=?, ?] -- 插入教师信息 INSERT INTO Teacher (id, name) VALUES (?, ?) [params=?, ?] INSERT INTO Teacher (id, name) VALUES (?, ?) [params=?, ?] -- 插入教师和学生关系信息 INSERT INTO Teacher_Student (TEACHERLIST_ID, STUDENTLIST_ID) VALUES (?, ?) [params=?, ?] INSERT INTO Teacher_Student (TEACHERLIST_ID, STUDENTLIST_ID) VALUES (?, ?) [params=?, ?] INSERT INTO Teacher_Student (TEACHERLIST_ID, STUDENTLIST_ID) VALUES (?, ?) [params=?, ?] INSERT INTO Teacher_Student (TEACHERLIST_ID, STUDENTLIST_ID) VALUES (?, ?) [params=?, ?] -- 查询教师信息 SELECT t0.id, t0.name FROM Teacher t0 SELECT t1.id, t1.name FROM Teacher_Student t0 INNER JOIN Student t1 ON t0.STUDENTLIST_ID = t1.id WHERE t0.TEACHERLIST_ID = ? [params=?] SELECT t1.id, t1.name FROM Teacher_Student t0 INNER JOIN Teacher t1 ON t0.TEACHERLIST_ID = t1.id WHERE t0.STUDENTLIST_ID = ? [params=?] SELECT t1.id, t1.name FROM Teacher_Student t0 INNER JOIN Teacher t1 ON t0.TEACHERLIST_ID = t1.id WHERE t0.STUDENTLIST_ID = ? [params=?] SELECT t1.id, t1.name FROM Teacher_Student t0 INNER JOIN Student t1 ON t0.STUDENTLIST_ID = t1.id WHERE t0.TEACHERLIST_ID = ? [params=?] teacher_id=51 teacher_name=教师1 teacher_students=[{"id":1,"name":"学生1","teacherList":[{"id":51,"name":"教师1","studentList":[{"$ref":"$[0]"},{"id":2,"name":"学生2","teacherList":[{"$ref":"$[0].teacherList[0]"},{"id":52,"name":"教师2","studentList":[{"$ref":"$[0]"},{"$ref":"$[0].teacherList[0].studentList[1]"}]}]}]},{"$ref":"$[0].teacherList[0].studentList[1].teacherList[1]"}]},{"$ref":"$[0].teacherList[0].studentList[1]"}] teacher_id=52 teacher_name=教师2 teacher_students=[{"id":1,"name":"学生1","teacherList":[{"id":51,"name":"教师1","studentList":[{"$ref":"$[0]"},{"id":2,"name":"学生2","teacherList":[{"$ref":"$[0].teacherList[0]"},{"id":52,"name":"教师2","studentList":[{"$ref":"$[0]"},{"$ref":"$[0].teacherList[0].studentList[1]"}]}]}]},{"$ref":"$[0].teacherList[0].studentList[1].teacherList[1]"}]},{"$ref":"$[0].teacherList[0].studentList[1]"}] -- 查询学生信息 SELECT t0.id, t0.name FROM Student t0 student_id=1 student_name=学生1 student_teacher=[{"id":51,"name":"教师1","studentList":[{"id":1,"name":"学生1","teacherList":[{"$ref":"$[0]"},{"id":52,"name":"教师2","studentList":[{"$ref":"$[0].studentList[0]"},{"id":2,"name":"学生2","teacherList":[{"$ref":"$[0]"},{"$ref":"$[0].studentList[0].teacherList[1]"}]}]}]},{"$ref":"$[0].studentList[0].teacherList[1].studentList[1]"}]},{"$ref":"$[0].studentList[0].teacherList[1]"}] student_id=2 student_name=学生2 student_teacher=[{"id":51,"name":"教师1","studentList":[{"id":1,"name":"学生1","teacherList":[{"$ref":"$[0]"},{"id":52,"name":"教师2","studentList":[{"$ref":"$[0].studentList[0]"},{"id":2,"name":"学生2","teacherList":[{"$ref":"$[0]"},{"$ref":"$[0].studentList[0].teacherList[1]"}]}]}]},{"$ref":"$[0].studentList[0].teacherList[1].studentList[1]"}]},{"$ref":"$[0].studentList[0].teacherList[1]"}]