Mybatis中使用collection進行多對多雙向關聯示例(含XML版與注解版)
XML版本:
實體類:
@Data @NoArgsConstructor public class Course { protected Integer id; protected String name; protected List<Student> students = new ArrayList<Student>(); public Course(Integer id) { this.id = id; } public Course(String name) { this.name = name; } public String toLazyString() { return "Course:{id: " + this.id + "; name: " + this.name + "}"; } }
@Data @ToString @NoArgsConstructor public class Student { protected Integer id; protected String name; protected List<Course> courses = new ArrayList<Course>(); public Student(Integer id) { this.id = id; } public Student(String name) { this.name = name; } public String toLazyString() { return "Student:{id: " + this.id + " ; name: " + this.name + "}"; } }
@Data @ToString @NoArgsConstructor public class StudentCourse { private Integer studentId; private Integer courseId; private Integer score; public StudentCourse(Integer studentId, Integer courseId) { this.studentId = studentId; this.courseId = courseId; } public StudentCourse(Integer score) { this.score = score; } }
@Data @ToString public class StudentExt extends Student { private String courseName; private String courseScore; }
Mapper接口:
public interface CourseMapper { public Course selectById(Integer id); public int insertCourse(Course course); public int updateCourse(Course course); public int deleteCourse(Course course); }
public interface StudentMapper { public Student selectById(Integer id); public int insertStudent(Student employee); public int updateStudent(Student employee); public int deleteStudent(Student employee); public List<Student> selectStudentByCourseAndScore(@Param("course") Course course, @Param("studentCourse") StudentCourse studentCourse); }
public interface StudentCourseMapper { public int insertStudentCourse(@Param("student") Student student, @Param("course") Course course); public int deleteStudentCourse(@Param("student") Student student, @Param("course") Course course); public int deleteStudentCourseByStudent(@Param("student") Student student); }
Mapper映射文件:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.sunwii.mybatis.mapper.CourseMapper"> <resultMap type="Course" id="CourseMap_basic"> <id property="id" column="cid" /> <result property="name" column="name" /> </resultMap> <resultMap type="Course" id="CourseMap" extends="CourseMap_basic"> <!-- 多對多關聯:使用select引用方式 --> <collection property="students" column="cid" ofType="Student" select="com.sunwii.mybatis.mapper.StudentMapper.selectByCourse" fetchType="lazy"> </collection> </resultMap> <select id="selectById" parameterType="Integer" resultMap="CourseMap"> select id as cid, name from t_course c where c.id=#{id} </select> <select id="selectByStudent" parameterType="Integer" resultMap="CourseMap_basic"> select c.id as cid, c.name from t_course c inner join t_student_course sc on c.id=sc.course_id and sc.student_id=#{studentId} </select> <insert id="insertCourse" parameterType="Course" keyColumn="id" keyProperty="id" useGeneratedKeys="true"> insert into t_course(name) values(#{name}) </insert> <update id="updateCourse" parameterType="Course"> update t_course set name=#{name} where id=#{id} </update> <delete id="deleteCourse" parameterType="Course"> delete from t_course where id=#{id} </delete> </mapper>
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.sunwii.mybatis.mapper.StudentMapper"> <resultMap type="Student" id="StudentMap_basic"> <id property="id" column="sid" /> <result property="name" column="name" /> </resultMap> <resultMap type="StudentExt" id="StudentMap_basic_ext" extends="StudentMap_basic"> <result property="courseName" column="cousename" /> <result property="courseScore" column="coursescore" /> </resultMap> <resultMap type="Student" id="StudentMap" extends="StudentMap_basic"> <!-- 多對多關聯:單向。方式四:使用select引用方式 --> <collection property="courses" column="sid" ofType="Course" select="com.sunwii.mybatis.mapper.CourseMapper.selectByStudent" fetchType="lazy" /> </resultMap> <select id="selectById" parameterType="Integer" resultMap="StudentMap"> select id as sid, name from t_student s where s.id=#{id} </select> <select id="selectByCourse" parameterType="Integer" resultMap="StudentMap_basic"> select s.id as sid, s.name from t_student s inner join t_student_course sc on s.id=sc.student_id and sc.course_id=#{courseId} </select> <select id="selectStudentByCourseAndScore" resultMap="StudentMap_basic_ext"> select s.id as sid, s.name,c.name as cousename,sc.score as coursescore from t_student s inner join t_student_course sc on s.id=sc.student_id and sc.score>=#{studentCourse.score} inner join t_course c on c.id=sc.course_id and c.name=#{course.name} </select> <insert id="insertStudent" parameterType="Student" keyColumn="id" keyProperty="id" useGeneratedKeys="true"> insert into t_student(name) values(#{name}) </insert> <update id="updateStudent" parameterType="Student"> update t_student set name=#{name} where id=#{id} </update> <delete id="deleteStudent" parameterType="Student"> delete from t_student where id=#{id} </delete> </mapper>
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.sunwii.mybatis.mapper.StudentCourseMapper"> <insert id="insertStudentCourse"> insert into t_student_course(student_id,course_id) values(#{student.id},#{course.id}) </insert> <delete id="deleteStudentCourse"> delete from t_student_course where student_id=#{student.id} and course_id=#{course.id} </delete> <delete id="deleteStudentCourseByStudent"> delete from t_student_course where student_id=#{student.id} </delete> </mapper>
業務層實現類:
@Service public class CourseServiceImpl implements CourseService { @Autowired private CourseMapper CourseMapper; @Override public Course getCourse(Integer id) { return CourseMapper.selectById(id); } @Override @Transactional public void insertCourse(Course course) { CourseMapper.insertCourse(course); } @Override @Transactional public void updateCourse(Course course) { CourseMapper.updateCourse(course); } @Override @Transactional public void deleteCourse(Course course) { CourseMapper.deleteCourse(course); } }
@Service public class StudentServiceImpl implements StudentService { @Autowired private StudentMapper studentMapper; @Autowired private CourseMapper courseMapper; @Autowired private StudentCourseMapper studentCourseMapper; @Override public Student getStudent(Integer id) { return studentMapper.selectById(id); } @Override @Transactional public void insertStudent(Student student) { List<Course> courses = student.getCourses(); // 如果需要的話,就先新增課程 if (courses != null) { for (Course course : courses) { if (course != null && course.getId() == null) { courseMapper.insertCourse(course); } } } studentMapper.insertStudent(student); // 添加選課表 if (courses != null) { for (Course course : courses) { if (course != null) { studentCourseMapper.insertStudentCourse(student, course); } } } } @Override @Transactional public void updateStudent(Student student) { List<Course> courses = student.getCourses(); if (courses != null) { // 如果需要的話,就先新增課程 for (Course course : courses) { if (course != null && course.getId() == null) { courseMapper.insertCourse(course); } } } studentMapper.updateStudent(student); // 修改選課表 if (courses != null) { //刪除舊的選課表記錄 studentCourseMapper.deleteStudentCourseByStudent(student); for (Course course : courses) { if (course != null) { studentCourseMapper.insertStudentCourse(student, course); } } } } @Override @Transactional public void deleteStudent(Student student) { studentMapper.deleteStudent(student); //刪除選課表記錄 studentCourseMapper.deleteStudentCourseByStudent(student); } @Override public List<Student> getStudentByCourseAndScore(String courseName,Integer score) { return studentMapper.selectStudentByCourseAndScore(new Course(courseName), new StudentCourse(score)); } }
測試類:
public class TestMany2Many { private ApplicationContext context = SpringUtil.getContext(); private StudentService studentService = (StudentService) context.getBean(StudentService.class); private CourseService courseService = (CourseService) context.getBean(CourseService.class); /** * 插入學生信息(可以同時新增不存在的課程,同時進行選課) */ @Test public void testStudentInsert() { // 多對多:添加。 Student student = new Student(); student.setName("sssss-1"); // 級聯新增的課程 Course course = new Course("course-1"); // 非新增的課程 Course course2 = courseService.getCourse(2); student.getCourses().add(course2); student.getCourses().add(course); studentService.insertStudent(student); } /** * 新增學生信息(可以暫時沒有選課) */ @Test public void testEmployeeInsert2() { // 多對多:添加。 Student student = new Student(); student.setName("sssss-2"); studentService.insertStudent(student); } /** * 查詢學生信息(可以有延遲加載選課記錄) */ @Test public void testStudentSelect() { // 多對一:查詢。 int id = 1; Student student = studentService.getStudent(id); System.out.println(student.toLazyString()); System.out.println(student); } /** * 更新學生信息(選課記錄是否要更改、是否要刪除和重新插入、是否要清空取決於程序) */ @Test public void testStudentUpdate() { // 多對多:添加。 int id = 4; Student student = studentService.getStudent(id); student.setName("sssss-444444444-2"); // 級聯新增的課程 Course course = new Course("course-xx"); // 非新增的課程 Course course2 = courseService.getCourse(1); student.getCourses().add(course); student.getCourses().add(course2); // 設置0長度代表清空課程 // student.setCourses(new ArrayList<Course>()); // 設置為null代表不修改 // student.setCourses(null); studentService.updateStudent(student); } /** * 刪除學生信息(會把選課記錄刪除) */ @Test public void testStudentDelete() { int id = 4; studentService.deleteStudent(new Student(id)); } /** * 查詢一門課程(以及學生信息) */ @Test public void testCourseSelect() { // 多對多:查詢 int id = 1; Course course = courseService.getCourse(id); System.out.println(course.toLazyString()); System.out.println(course); } /** * 查詢“數學"成績90分以上的學生 */ @Test public void testCourseWithScoreSelect() { // 多對多:查詢 int id = 1; String courseName = "數學"; Integer score = 90; List<Student> students = studentService.getStudentByCourseAndScore(courseName, score); for (Student student : students) { System.out.print(student.toLazyString()+"-------"); StudentExt studentExt = (StudentExt)student; System.out.println(studentExt.getCourseName()+":"+studentExt.getCourseScore()); //System.out.println(courseName+":"+score); } //結果: //Student:{id: 1 ; name: 小紅}-------數學:95 //Student:{id: 3 ; name: 小青}-------數學:92 } }
注解版本:
注解版本只是將Mapper映射文件去掉,將映射注解到Mapper接口中(如果需要則再添加動態sql提供器類),其它東西不變。
Mapper接口(注解版):
public interface CourseMapper { public static final String selectById = "select id as cid,name from t_course where id=#{id}"; public static final String selectByStudent = "" + "select c.id as cid, c.name from t_course " + "c inner join t_student_course sc on " + "c.id=sc.course_id and sc.student_id=#{studentId}"; public static final String insert = "insert into t_course(name) values(#{name})"; public static final String update = "update t_course set name=#{name}"; public static final String delete = "delete from t_course where id=#{id}"; public static final String many2many = "com.sunwii.mybatis.mapper.StudentMapper.selectByCourse"; @Select(selectById) @Results(id = "CourseMap", value = { @Result(property = "id", column = "cid"), @Result(property = "name", column = "name"), @Result(property = "students", column = "cid", many = @Many( select = many2many, fetchType = FetchType.LAZY)) }) public Course selectById(Integer id); @Select(selectByStudent) @Results(id = "CourseMap_basic", value = { @Result(property = "id", column = "cid"), @Result(property = "name", column = "name") }) public List<Course> selectByStudent(Student studentId); @Insert(insert) @Options(keyColumn = "id", keyProperty = "id", useGeneratedKeys = true) public int insertCourse(Course course); @Update(update) public int updateCourse(Course course); @Delete(delete) public int deleteCourse(Course course); }
public interface StudentMapper { public static final String selectById = "select id as sid,name from t_student where id=#{id}"; public static final String selectByCourse = "" + "select s.id as sid, s.name from t_student s " + " inner join t_student_course sc" + " on s.id=sc.student_id and sc.course_id=#{courseId}"; public static final String selectStudentByCourseAndScore = "" + "select s.id as sid, s.name,c.name as cousename,sc.score as coursescore " + "from t_student s inner join t_student_course sc " + "on s.id=sc.student_id and sc.score>=#{studentCourse.score} " + "inner join t_course c on c.id=sc.course_id and c.name=#{course.name}"; public static final String insert = "insert into t_student(name) values(#{name})"; public static final String update = "update t_student set name=#{name} where id=#{id}"; public static final String delete = "delete from t_student where id=#{id}"; public static final String many2many = "com.sunwii.mybatis.mapper.CourseMapper.selectByStudent"; @Select(selectById) @Results(id="StudentMap",value= { @Result(property = "id", column = "sid"), @Result(property = "name", column = "name"), @Result(property = "courses",column = "sid", many=@Many( select = many2many, fetchType = FetchType.LAZY )) }) public Student selectById(Integer id); @Insert(insert) @Options(keyColumn = "id", keyProperty = "id", useGeneratedKeys = true) public int insertStudent(Student employee); @Update(update) public int updateStudent(Student employee); @Delete(delete) public int deleteStudent(Student employee); @Select(selectByCourse) @Results(id="StudentMap_basic", value = { @Result(property = "id", column = "sid"), @Result(property = "name", column = "name") }) public List<Student> selectByCourse(Integer courseId); @Select(selectStudentByCourseAndScore) @Results(id="StudentMap_basic_ext", value = { @Result(property = "id", column = "sid"), @Result(property = "name", column = "name"), }) public List<Student> selectStudentByCourseAndScore(@Param("course") Course course, @Param("studentCourse") StudentCourse studentCourse); }
public interface StudentCourseMapper { public static final String insert="insert into t_student_course(student_id,course_id) values(#{student.id},#{course.id})"; public static final String delete="delete from t_student_course where student_id=#{student.id} and course_id=#{course_id}"; public static final String deleteByStudent="delete from t_student_course where student_id=#{student.id}"; @Insert(insert) public int insertStudentCourse(@Param("student") Student student, @Param("course") Course course); @Delete(delete) public int deleteStudentCourse(@Param("student") Student student, @Param("course") Course course); @Delete(deleteByStudent) public int deleteStudentCourseByStudent(@Param("student") Student student); }
由於注解版在定義resultMap(即@Results)時無法使用type屬性定義返回的封裝類型,所以測試類需要修改一點:
/** * 查詢“數學"成績90分以上的學生 */ @Test public void testCourseWithScoreSelect() { int id = 1; String courseName = "數學"; Integer score = 90; List<Student> students = studentService.getStudentByCourseAndScore(courseName, score); for (Student student : students) { System.out.print(student.toLazyString()+"-------"); //注解版無法使用resultMap的type屬性,不能直接轉化 //StudentExt studentExt = (StudentExt)student; //System.out.println(studentExt.getCourseName()+":"+studentExt.getCourseScore()); System.out.println(courseName+":"+score); } //結果: //Student:{id: 1 ; name: 小紅}-------數學:95 //Student:{id: 3 ; name: 小青}-------數學:92 }