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),結果也一樣)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM