Mybatis的OneToMany,ManyToOne和解决N+1查询问题

OneToMany

1.在”one”的实体类总添加many的一对多关系:

private List<Student> studentList;//(get和set方法略)

2.在”many”的配置文件中添加查询的方法:

  <!--老师关联学生-->
    <select id="selectStudentByTeacherId" parameterType="java.lang.Integer" resultMap="BaseResultMap">
        select * from student where teacher_id=#{teacherId,jdbcType=INTEGER}
    </select>
<!--
    id为查询的id,自己取个名;
    parameterType为参数类型;
    resultMap为查询结果转换为java的类属性
-->

3.在”one”的配置文件的resultMap中添加一个集合:

 <!--OneToMany老师关联学生-->
      <collection property="studentList" column="teacher_id" ofType="com.shinowit.entity.Student" select="com.shinowit.dao.mapper.StudentMapper.selectStudentByTeacherId">
      </collection>
<!--
property为one中实体类添加的集合的pojo对象;
column为根据哪个字段查询,一般是one的主键;
ofType为单个查询结果的数据类型;
select为many的配置文件的<mapper>标签的namespace+many中刚才添加的查询方法的id:namespace+selectStudentByTeacherId
-->

4.编写单元测试

    @Resource
    private Teacher1Mapper teacher1DAO;
    protected final Logger logger = Logger.getLogger(getClass());
    @Test
    public void test1() {
        Teacher1 teacher11=teacher1DAO.selectByPrimaryKey(1);
        for(Student stu:teacher11.getStudentList()){
            logger.debug(stu.getName());
        }
     }

ManyToOne

1.在”many”的实体类总添加one的多对一关系:

  private Teacher1 tea;//(get和set方法略)

2.在many的配置文件中添加映射的关联(association):
(因为查many的数据本质是从xml文件查的,所以要在xml文件中把刚才的tea字段添加到映射result中)

 <!--关联老师-->
<association property="tea" column="teacher_id" javaType="com.shinowit.entity.Teacher1"         select="com.shinowit.dao.mapper.Teacher1Mapper.selectByPrimaryKey"/>
<!--
  property为many实体类中添加的pojo对象;
  column意思是用哪个字段去做关联查询;
  javaType为这个字段是什么类型的;
  select为数据取出的方法,用one的配置文件的<mapper>标签的namespace+one中的根据主键查询的方法id:namespace+selectByPrimaryKey
-->

3.编写单元测试

    @Resource
    private StudentMapper studentDAO;
    protected final Logger logger = Logger.getLogger(getClass());
    @Test
    public void test1() {
        Student stu=studentDAO.selectByPrimaryKey(2);//ManyToOne查学生信息,会把老师信息一同查出
        logger.debug(stu.getTea().getName());
          }

解决N+1查询问题

方法一:

  • 在one的<mapper>标签下添加一个<cache/>标签

方法二:
1. 在many的实体类中添加要附带查出来的字段,如:

 private String teacherName;//(get和set方法略)

2.在many的Mapper中添加一个接口,如:

List<Student> selectStudentWithTeacherNameByPrimaryKey(Integer student_id);

3.在many的xml文件最下面新添加一个和一个,如:

<!--解决N+1问题-->
<resultMap id="resultMapWithTeacherName" type="com.shinowit.entity.Student" extends="BaseResultMap">
        <result column="teacher_name" property="teacherName" jdbcType="VARCHAR"/>
</resultMap>             
<!--
    type为实体类类型              
    extends="BaseResultMap"就照着抄上面的就行               
    column是要查询的对应的数据库的字段                
    property是实体类的pojo对象对应的数据库的字段类型 
-->    

<!--解决N+1问题的查询-->
    <select id="selectStudentWithTeacherNameByPrimaryKey" parameterType="java.lang.Integer" resultMap="resultMapWithTeacherName">
        select a.*,b.name as teacher_name from student a inner join teacher1 b on a.teacher_id=b.teacher_id where student_id=#{student_id,jdbcType=INTEGER}
    </select>               
<!--
    id是接口中的方法名               
    resultMap是上面<resultMap>的id               
    中间的sql语句的{}中的student_id是接口中的参数
-->

4.编写单元测试

    @Resource
    private StudentMapper studentDAO;
    protected final Logger logger = Logger.getLogger(getClass());
    @Test
List<Student> studentList=studentDAO.selectStudentWithTeacherNameByPrimaryKey(1);
    //用自己写sql语句的方法解决N+1查询问题                  logger.debug(studentList.get(0).getTeacherName());
                    }

注:尽量少用collection 和association 标签,因是他是N+1查询,而hibernate就是N+1查询

方法二扩展:

1.在many的实体类中添加要附带查出来的字段,如:

private String teacherName;//(get和set方法略)

2.在many的Mapper中添加一个接口,如:

List<Student> selectStudentWithTeacherNameByPrimaryKey(StudentExample example);

3.在many的xml文件最下面新添加一个和一个,如:

<!--解决N+1问题-->
    <resultMap id="resultMapWithTeacherName" type="com.shinowit.entity.Student" extends="BaseResultMap">
        <result column="teacher_name" property="teacherName" jdbcType="VARCHAR"/>
    </resultMap>
<!--解决N+1问题的查询-->
    <select id="selectStudentWithTeacherNameByPrimaryKey" parameterType="com.shinowit.entity.StudentExample" resultMap="resultMapWithTeacherName">
        select *,(select name from teacher1 where teacher1.teacher_id=student.teacher_id) as teacher_name from student
        <if test="_parameter != null">
            <include refid="Example_Where_Clause"/>
        </if>
        <if test="orderByClause != null">
            order by ${orderByClause}
        </if>
    </select>

4.编写单元测试

    @Resource
    private Teacher1Mapper teacher1DAO;
    protected final Logger logger = Logger.getLogger(getClass());
    @Test
    public void test1() {
      StudentExample ex=new StudentExample();//比较复杂的用StudentExample作参数的方法解决N+1问题
        ex.createCriteria().andTeacherIdEqualTo(1);
        List<Student> studentList=studentDAO.selectStudentWithTeacherNameByPrimaryKey(ex);
        for(Student student:studentList){
            logger.debug(student.getTeacherName());
        }}

版权声明:本文为d470969047h原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。