zoukankan      html  css  js  c++  java
  • SQL映射文件-----MySQL关系映射【1对1,1对多,多对多】

    SSM框架下,mapper.xml 中 association 标签和 collection 标签的使用

    当数据库中表与表之间有关联时,在对数据库进行操作时,就不只是针对某一张表了,需要联表查询

    MyBatis中如何实现联表查询

    1、首先新建两张表

    学生表(student

    • ID:stu_id
    • 姓名:stu_name
    • 年龄:stu_age
    • 性别:stu_gender
    • 所在班级:g_id

    班级表(grade

    • ID:g_id
    • 班级名称:g_name

    学生表和班级表通过 g_id 进行关联,一个班级对应多个学生

    2、创建相应的实体类和mapper接口

    (1)创建 Student 类和 Grade 类(包名:com.bwlu.bean

    (2)创建 StudentMapper 接口和 GradeMapper 接口和相应的 XML 文件(使用逆向生成可直接生成)

     StudentMapper.java 接口

    Student selectByPrimaryKey(Integer stuId);//按主键查询一条记录

     StudentMapper.xml

    <mapper namespace="com.bwlu.mapper.StudentMapper" >
      <resultMap id="BaseResultMap" type="com.bwlu.bean.Student" >
        <id column="stu_id" property="stuId" jdbcType="INTEGER" />
        <result column="stu_name" property="stuName" jdbcType="VARCHAR" />
        <result column="stu_age" property="stuAge" jdbcType="INTEGER" />
        <result column="stu_gender" property="stuGender" jdbcType="INTEGER" />
        <result column="g_id" property="gId" jdbcType="INTEGER" />
      </resultMap>
      <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
        select stu_id, stu_name, stu_age, stu_gender, g_id from student 
        where stu_id = #{stuId,jdbcType=INTEGER}
      </select>
    </mapper>

     GradeMapper.java

    Grade selectByPrimaryKey(Integer gId);//按主键查询一条记录

     GradeMapper.xml

    <mapper namespace="com.bwlu.mapper.GradeMapper" >
      <resultMap id="BaseResultMap" type="com.bwlu.bean.Grade" >
        <id column="g_id" property="gId" jdbcType="INTEGER" />
        <result column="g_name" property="gName" jdbcType="VARCHAR" />
      </resultMap>
      <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
        select g_id, g_name from grade
        where g_id = #{gId,jdbcType=INTEGER}
      </select>
    </mapper>

    3、在sql映射文件中写映射sql语句【联合查询:级联属性封装结果集】

    3.1第一种 

    (1)在 Student.java 中将 g_id 属性换成班级类型(Grade),并添加相应的getter和setter方法

    //private Integer g_id;
    private Grade grade;
    public Grade getGrade() {
        return grade;
    }
    public void setGrade(Grade grade) {
        this.grade = grade;
    }

    (2)在 xml 中封装结果集,并编写相应的 sql 语句

    <resultMap id="BaseResultMap" type="com.bwlu.bean.Student" >
      <id column="stu_id" property="stuId" jdbcType="INTEGER" />
      <result column="stu_name" property="stuName" jdbcType="VARCHAR" />
      <result column="stu_age" property="stuAge" jdbcType="INTEGER" />
      <result column="stu_gender" property="stuGender" jdbcType="INTEGER" />
      <result column="g_id" property="grade.gId" jdbcType="INTEGER" />
      <result column="g_name" property="grade.gName" jdbcType="VARCHAR" />
    </resultMap>
    <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
      select stu_id, stu_name, stu_age, stu_gender, g.g_id, g_name
      from student s,grade g
      where s.g_id = g.g_id AND stu_id = #{stuId,jdbcType=INTEGER}
    </select>

    (3)测试

    @Autowired
    private StudentMapper studentMapper;
    @Test
    public void testAssociation() {
        Student student = studentMapper.selectByPrimaryKey(6);
        System.out.println(student);//Student [stuId=6, stuName=lixiang, stuAge=22, stuGender=1, grade=Grade [gId=3, gName=软件(3)班]]
    }

    3.2第二种

    (1)在 Student.java 中将 g_id 属性换成班级类型(Grade),并添加相应的getter和setter方法,同 3.1 的(1)

    (2)使用association来定义关联对象的规则【比较正规的,推荐的方式】

    <resultMap id="BaseResultMap" type="com.bwlu.bean.Student" >
      <id column="stu_id" property="stuId" jdbcType="INTEGER" />
      <result column="stu_name" property="stuName" jdbcType="VARCHAR" />
      <result column="stu_age" property="stuAge" jdbcType="INTEGER" />
      <result column="stu_gender" property="stuGender" jdbcType="INTEGER" />
      <!-- association可以指定联合的javaBean对象
        property="grade":指定哪个属性是联合的对象
        javaType:指定这个属性对象的类型【不能省略】-->
      <association property="grade" javaType="com.bwlu.bean.Grade">
          <id column="g_id" property="gId" jdbcType="INTEGER"/>
          <result column="g_name" property="gName" jdbcType="VARCHAR"/>
      </association>
    </resultMap>
    <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
      select stu_id, stu_name, stu_age, stu_gender, g.g_id, g_name
      from student s,grade g
      where s.g_id = g.g_id AND stu_id = #{stuId,jdbcType=INTEGER}
    </select>

    (3)测试(同 3.1 的(3),结果也一样)

     3.3第三种

    (1)在 Student.java 中将 g_id 属性换成班级类型(Grade),并添加相应的getter和setter方法,同 3.1 的(1)

    (2)使用Association进行分步查询【上述结果相当于使用嵌套结果集的形式】

    <resultMap id="BaseResultMap" type="com.bwlu.bean.Student" >
      <id column="stu_id" property="stuId" jdbcType="INTEGER" />
      <result column="stu_name" property="stuName" jdbcType="VARCHAR" />
      <result column="stu_age" property="stuAge" jdbcType="INTEGER" />
      <result column="stu_gender" property="stuGender" jdbcType="INTEGER" />
      <!-- 使用association进行分步查询 
         1.先按照学生id查询学生信息
         2.根据查询学生信息中g_id值去班级表查出班级信息
         3.将班级信息设置到学生中:
        association定义关联对象的封装规则
        select:表明当前属性是调用指定的方法查出的结果
        column:指定将哪一列的值传给这个方法
        流程:使用select指定的方法(传入column指定的这列参数的值)查出对象,并封装给property指定的属性。-->
      <association property="grade" select="getGradeById" column="g_id"></association>
    </resultMap>
    <select id="getGradeById"resultType="com.bwlu.bean.Grade" parameterType="java.lang.Integer" >
      select g_id, g_name from grade 
      where g_id = #{gId,jdbcType=INTEGER}
    </select>
    <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
      select stu_id, stu_name, stu_age, stu_gender, g_id
      from student
      where stu_id = #{stuId,jdbcType=INTEGER}
    </select>

     注:使用 resultType 返回值类型进行接收,必须使用驼峰式命名,使数据库中的字段和实体类中的字段对应。

     (3)测试(同 3.1 的(3),结果也一样)

     (2)中也可以指定为 GradeMapper 下的方法。

    <association property="grade" select="com.bwlu.mapper.GradeMapper.selectByPrimaryKey" column="g_id"></association>

    懒加载机制【按需加载,也叫懒加载】
    3.3 分步查询中,每次查询 Student 对象的时候,都将关联 Grade 的对象查询出来了。

    使用延迟加载,可以在需要 班级 信息的时候,再去查询,不需要的时候就不用查询。

    在 MyBatis 的全局配置文件中,加入两个配置

    <settings>
        <!-- 驼峰式命名 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!-- 开启懒加载机制 ,默认值为true-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 开启的话,每个属性都会直接全部加载出来;禁用的话,只会按需加载出来 -->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

    这样,当我们查询 Student 对象的时候,

    如果只输出学生姓名,就不会执行查询班级信息的 sql 语句(只执行一条 sql 语句),

    select stu_id, stu_name, stu_age, stu_gender, g_id from student where stu_id = ?   Parameters: 6(Integer)

    当需要班级信息的时候才会执行,(执行两条 sql 语句)

    select stu_id, stu_name, stu_age, stu_gender, g_id from student where stu_id = ?    Parameters: 6(Integer)

    select g_id, g_name from grade where g_id = ?    Parameters: 3(Integer)

    3.4 上述是在多端(学生)查询一端(班级)的信息,用 association,当我们在一端查询多端信息的时候,需要使用 collection,查出的是一个集合

     (1)在班级类(Grade)类中添加一个属性 List<Student> stuList,并添加相应的 gettersetter 方法

    private List<Student> stuList;
    public List<Student> getStuList() {
        return stuList;
    }
    public void setStuList(List<Student> stuList) {
        this.stuList = stuList;
    }

    (2)使用collection标签定义关联的集合类型元素的封装规则【collection:嵌套结果集的方式】

    <resultMap id="BaseResultMap" type="com.bwlu.bean.Grade" >
      <id column="g_id" property="gId" jdbcType="INTEGER" />
      <result column="g_name" property="gName" jdbcType="VARCHAR" />
      <!-- 
        collection:定义关联集合类型的属性的封装规则
        ofType:指定集合里面元素的类型
      -->
      <collection property="stuList" ofType="com.bwlu.bean.Student">
        <!-- 定义这个集合中元素的封装规则 -->
          <id column="stu_id" property="stuId" jdbcType="INTEGER" />
        <result column="stu_name" property="stuName" jdbcType="VARCHAR" />
        <result column="stu_age" property="stuAge" jdbcType="INTEGER" />
        <result column="stu_gender" property="stuGender" jdbcType="INTEGER" />
      </collection>
    </resultMap>
    <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
      select g.g_id, g_name, stu_id, stu_name, stu_age, stu_gender
      from grade g,student s
      where g.g_id = s.g_id AND g.g_id = #{gId,jdbcType=INTEGER}
    </select>

    (3)测试

    @Autowired
    private GradeMapper gradeMapper;
    @Test
    public void testCollection() {
        Grade grade = gradeMapper.selectByPrimaryKey(3);
        List<Student> stuList = grade.getStuList();
        for(Student stu:stuList){
            System.out.println(stu);
            //Student [stuId=3, stuName=fenghen, stuAge=12, stuGender=1, grade=null]
            //Student [stuId=6, stuName=lixiang, stuAge=22, stuGender=1, grade=null]
        }
    }

    注意:grade为null,因为 Student 和 Grade 相互嵌套,如果用 resultMap 进行接收的话,会相互嵌套,最终导致栈溢出,应用 resultType 进行接收,嵌套的类型为 null 值。

    3.5 使用分步查询结果集的方式

    (1)在班级类(Grade)类中添加一个属性 List<Student> stuList,并添加相应的 getter 和 setter 方法,同 3.4 中的(1)

    (2)在 GradeMapper.xml 中添加如下方法

    <resultMap id="BaseResultMap" type="com.bwlu.bean.Grade" >
      <id column="g_id" property="gId" jdbcType="INTEGER" />
      <result column="g_name" property="gName" jdbcType="VARCHAR" />
      <collection property="stuList" select="com.bwlu.mapper.StudentMapper.selectByGId" column="g_id"></collection>
    </resultMap>
    <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
      select g_id, g_name from grade
      where g_id = #{gId,jdbcType=INTEGER}
    </select>

    StudentMapper.xml 中添加如下方法 selectByGId :根据 g_id 查询学生集合

    <select id="selectByGId" resultType="com.bwlu.bean.Student" parameterType="java.lang.Integer" >
      select 
      stu_id, stu_name, stu_age, stu_gender,g_id
      from student 
      where g_id = #{gId,jdbcType=INTEGER}
    </select>

     (3)测试(同 3.4 的(3),结果也一样)

  • 相关阅读:
    java中的堆、栈、常量池
    java中int和Integer的区别
    python linecache模块读取文件的方法
    Python 字符串中 startswith()方法
    Python中的filter()函数的用法
    python sort、sorted高级排序技巧
    二级指针内存模型(一)
    Linux下多线程模拟停车场停车
    linux线程操作
    C语言实现多线程排序
  • 原文地址:https://www.cnblogs.com/lixiang1993/p/7482192.html
Copyright © 2011-2022 走看看