Mybatis進階:接口代理方式實現dao層,動態sql語句,分頁插件,Mybatis多表操做

知識點梳理

詳細講義

一.接口代理方式實現Dao ***

1.1 代理開發方式介紹

  • 採用 Mybatis 的代理開發方式實現 DAO 層的開發,這種方式是咱們後面進入企業的主流。java

  • Mapper 接口開發方法只須要程序員編寫Mapper 接口(至關於Dao 接口),由Mybatis 框架根據接口定義建立接口的動態代理對象,代理對象的方法體同上邊Dao接口實現類方法mysql

  • 總結:接口代理方式,其實就咱們本身不用實現MapperImpl(持久層實現類),mybatis經過接口代理的方式幫助咱們實現git

  • Mapper 接口開發須要遵循如下規範:程序員

    1) Mapper.xml文件中的namespace與mapper接口的全限定名相同github

    2) Mapper接口方法名和Mapper.xml中定義的每一個statement的id相同sql

    3) Mapper接口方法的輸入參數類型和mapper.xml中定義的每一個sql的parameterType的類型相同數據庫

    4) Mapper接口方法的輸出參數類型和mapper.xml中定義的每一個sql的resultType的類型相同apache

  • 以下圖:session

 

 

1.2 代碼實現

  • 實現步驟:mybatis

  1. 刪除 mapper 層接口的實現類(新建一個項目mybatis02,將第一天的代碼所有複製過來)

  2. 修改映射配置文件

    <!-- 將命名空間修改成StudentMapper全路徑名-->
    <mapper namespace="com.itheima.mapper.StudentMapper">
  3. 修改 service 層接口的實現類,採用接口代理方式實現功能(由於如今沒有持久層實現類了,因此業務層沒法直接調用,須要本身實現而且調用代理接口方式的MapperImpl)

    package com.itheima.service.impl;

    import com.itheima.bean.Student;
    import com.itheima.mapper.StudentMapper;
    import com.itheima.service.StudentService;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;

    import java.io.IOException;
    import java.io.InputStream;
    import java.util.List;
    /*
       業務層實現類
    */
    public class StudentServiceImpl implements StudentService {

       @Override
       public List<Student> selectAll() {
           List<Student> list = null;
           SqlSession sqlSession = null;
           InputStream is = null;
           try{
               //1.加載核心配置文件
               is = Resources.getResourceAsStream("MyBatisConfig.xml");

               //2.獲取SqlSession工廠對象
               SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

               //3.經過工廠對象獲取SqlSession對象
               sqlSession = sqlSessionFactory.openSession(true);

               //4.獲取StudentMapper接口的實現類對象
               StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl();

               //5.經過實現類對象調用方法,接收結果
               list = mapper.selectAll();

          } catch (Exception e) {

          } finally {
               //6.釋放資源
               if(sqlSession != null) {
                   sqlSession.close();
              }
               if(is != null) {
                   try {
                       is.close();
                  } catch (IOException e) {
                       e.printStackTrace();
                  }
              }
          }

           //7.返回結果
           return list;
      }

       @Override
       public Student selectById(Integer id) {
           Student stu = null;
           SqlSession sqlSession = null;
           InputStream is = null;
           try{
               //1.加載核心配置文件
               is = Resources.getResourceAsStream("MyBatisConfig.xml");

               //2.獲取SqlSession工廠對象
               SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

               //3.經過工廠對象獲取SqlSession對象
               sqlSession = sqlSessionFactory.openSession(true);

               //4.獲取StudentMapper接口的實現類對象
               StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl();

               //5.經過實現類對象調用方法,接收結果
               stu = mapper.selectById(id);

          } catch (Exception e) {

          } finally {
               //6.釋放資源
               if(sqlSession != null) {
                   sqlSession.close();
              }
               if(is != null) {
                   try {
                       is.close();
                  } catch (IOException e) {
                       e.printStackTrace();
                  }
              }
          }

           //7.返回結果
           return stu;
      }

       @Override
       public Integer insert(Student stu) {
           Integer result = null;
           SqlSession sqlSession = null;
           InputStream is = null;
           try{
               //1.加載核心配置文件
               is = Resources.getResourceAsStream("MyBatisConfig.xml");

               //2.獲取SqlSession工廠對象
               SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

               //3.經過工廠對象獲取SqlSession對象
               sqlSession = sqlSessionFactory.openSession(true);

               //4.獲取StudentMapper接口的實現類對象
               StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl();

               //5.經過實現類對象調用方法,接收結果
               result = mapper.insert(stu);

          } catch (Exception e) {

          } finally {
               //6.釋放資源
               if(sqlSession != null) {
                   sqlSession.close();
              }
               if(is != null) {
                   try {
                       is.close();
                  } catch (IOException e) {
                       e.printStackTrace();
                  }
              }
          }

           //7.返回結果
           return result;
      }

       @Override
       public Integer update(Student stu) {
           Integer result = null;
           SqlSession sqlSession = null;
           InputStream is = null;
           try{
               //1.加載核心配置文件
               is = Resources.getResourceAsStream("MyBatisConfig.xml");

               //2.獲取SqlSession工廠對象
               SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

               //3.經過工廠對象獲取SqlSession對象
               sqlSession = sqlSessionFactory.openSession(true);

               //4.獲取StudentMapper接口的實現類對象
               StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl();

               //5.經過實現類對象調用方法,接收結果
               result = mapper.update(stu);

          } catch (Exception e) {

          } finally {
               //6.釋放資源
               if(sqlSession != null) {
                   sqlSession.close();
              }
               if(is != null) {
                   try {
                       is.close();
                  } catch (IOException e) {
                       e.printStackTrace();
                  }
              }
          }

           //7.返回結果
           return result;
      }

       @Override
       public Integer delete(Integer id) {
           Integer result = null;
           SqlSession sqlSession = null;
           InputStream is = null;
           try{
               //1.加載核心配置文件
               is = Resources.getResourceAsStream("MyBatisConfig.xml");

               //2.獲取SqlSession工廠對象
               SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

               //3.經過工廠對象獲取SqlSession對象
               sqlSession = sqlSessionFactory.openSession(true);

               //4.獲取StudentMapper接口的實現類對象
               StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl();

               //5.經過實現類對象調用方法,接收結果
               result = mapper.delete(id);

          } catch (Exception e) {

          } finally {
               //6.釋放資源
               if(sqlSession != null) {
                   sqlSession.close();
              }
               if(is != null) {
                   try {
                       is.close();
                  } catch (IOException e) {
                       e.printStackTrace();
                  }
              }
          }

           //7.返回結果
           return result;
      }
    }
  • 最後測試:經過StudentController的測試類來直接測試,可以測試經過便可

1.3 源碼分析

  • 分析動態代理對象如何生成的?

    • 經過動態代理開發模式,咱們只編寫一個接口,不寫實現類,咱們經過 getMapper() 方法最終獲取到 org.apache.ibatis.binding.MapperProxy 代理對象,而後執行功能,

    • 而這個代理對象正是 MyBatis 使用了 JDK 的動態代理技術,幫助咱們生成了代理實現類對象。從而能夠進行相關持久化操做。

    • 跟蹤getMapper方法,最終能夠跟蹤到以下代碼:這個代碼就是咱們以前本身實現動態代理的代碼:

       

       

  • 分析方法是如何執行的?

    • 分析過程:

      • 跟蹤mapper.insert方法,代碼打斷點,而後調試跟蹤

      • 代碼執行到insert以後,進入方法的執行,而後就進入到了invoke方法(動態代理執行方法,都會執行invoke)

      • 在invoke中調用了mapperMethod.execute()方法

      • 這個方法中經過 switch 語句根據操做類型來判斷是新增、修改、刪除、查詢操做,

      • 最後一步回到了 MyBatis 最原生的 SqlSession 方式來執行增刪改查

         

         

1.4 @Param

  1. 給映射文件的sql傳遞多個參數,除了封裝對象,還能夠經過註解Param來實現

  2. 代碼:StudentMapper增長

    //根據姓名或年齡查詢
       public abstract List<Student> selectByNameOrAge(@Param("p1") String name , @Param("p2") Integer age);
  3. 配置:

    <select id="selectByNameOrAge" resultType="student" >
       <include refid="select"/> WHERE name = #{p1} OR age = #{p2}
    </select>
  4. 經過@Param配置的參數名,在映射中就能夠經過#{}來獲取

1.5 知識小結

  • 接口代理方式可讓咱們只編寫接口便可,而實現類對象由 MyBatis 生成

  • 實現規則 :

    1. 映射配置文件中的名稱空間必須和 Dao 層接口的全類名相同

    2. 映射配置文件中的增刪改查標籤的 id 屬性必須和 Dao 層接口的方法名相同

    3. 映射配置文件中的增刪改查標籤的 parameterType 屬性必須和 Dao 層接口方法的參數相同

    4. 映射配置文件中的增刪改查標籤的 resultType 屬性必須和 Dao 層接口方法的返回值相同

  • 獲取動態代理對象

    • 獲取動態代理對象 SqlSession 功能類中的 getMapper() 方法

二. 動態sql語句

2.1 動態sql語句概述

  • Mybatis 的映射文件中,前面咱們的 SQL 都是比較簡單的,

  • 有些時候業務邏輯複雜時,咱們的 SQL是動態變化的,此時在前面的學習中咱們的 SQL 就不能知足要求了。

  • 例如,有時候查詢條件是三個,有時候是兩個:

     

     

  • 代碼:

    1. StudentMapper.xml增長多條件sql

       

       

    2. Mapper接口:增長多條件查詢方法

      //多條件查詢
      public abstract List<Student> selectCondition(Student stu);
    3. 測試類:com.itheima.dynamic.Test01

       @Test
         public void selectCondition() throws Exception{
             //1.加載核心配置文件
             InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");

             //2.獲取SqlSession工廠對象
             SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

             //3.經過工廠對象獲取SqlSession對象
             SqlSession sqlSession = sqlSessionFactory.openSession(true);

             //4.獲取StudentMapper接口的實現類對象
             StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

             Student stu = new Student();
             stu.setId(2);
             stu.setName("李四");
             stu.setAge(24);

             //5.調用實現類的方法,接收結果
             List<Student> list = mapper.selectCondition(stu);

             //6.處理結果
             for (Student student : list) {
                 System.out.println(student);
            }

             //7.釋放資源
             sqlSession.close();
             is.close();
        }
    4. 3個條件結果

       

       

    5. 2個條件(將setAge屏蔽掉)結果:若是有一個參數沒有傳遞,默認是null,這確定查詢不到數據

       

       

      • 那如何解決這種問題呢?咱們可能會根據不一樣需求要利用同一個功能,可是查詢條件可能會變化

      • 在映射文件中如何動態配置sql呢?

      • 利用動態sql標籤

  • 動態sql標籤

     

     

2.2 動態 SQL 之<if> ***

  • 咱們根據實體類的不一樣取值,使用不一樣的 SQL語句來進行查詢。

  • 好比在 id若是不爲空時能夠根據id查詢,若是username 不一樣空時還要加入用戶名做爲條件。

  • 這種狀況在咱們的多條件組合查詢中常常會碰到。

  • 咱們須要動態sql標籤where和if。

  • <where>:條件標籤,若是有動態條件,則使用該標籤代替where關鍵字

  • <if>:條件判斷標籤

     <if test="條件判斷">
    拼接的查詢條件
    </if>
  • 以下圖:

<select id="selectCondition" resultType="student" parameterType="student">
  select * from student
   <where>
       <if test="id != null">
          id = #{id}
       </if>
       <if test="name != null">
          AND name = #{name} <!--若是沒有傳遞id,會不會直接是where and name=xxx,不會,mybatis會作特殊處理-->
       </if>
       <if test="age != null">
          AND age = #{age}
       </if>
   </where>
</select>
  • 總結語法:

<where>:條件標籤。若是有動態條件,則使用該標籤代替 where 關鍵字。
<if>:條件判斷標籤。語法以下:
<if test=「條件判斷」>
拼接的查詢條件
</if>

2.3 動態 SQL 之<foreach> ***

 

 

  • 接下來咱們來寫代碼:

  • 增長映射配置:

<select id="selectByIds" resultType="student" parameterType="list">
   <include refid="select"/>
   <where>
       <foreach collection="list" open="id IN (" close=")" item="id" separator=",">
          #{id}
       </foreach>
   </where>
</select>
  • 增長接口:

//根據多個id查詢
public abstract List<Student> selectByIds(List<Integer> ids);
  • Test01中增長測試方法:

@Test
public void selectByIds() throws Exception{
   //1.加載核心配置文件
   InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");

   //2.獲取SqlSession工廠對象
   SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

   //3.經過工廠對象獲取SqlSession對象
   SqlSession sqlSession = sqlSessionFactory.openSession(true);

   //4.獲取StudentMapper接口的實現類對象
   StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

   List<Integer> ids = new ArrayList<>();
   ids.add(1);
   ids.add(2);
   ids.add(3);

   //5.調用實現類的方法,接收結果
   List<Student> list = mapper.selectByIds(ids);

   //6.處理結果
   for (Student student : list) {
       System.out.println(student);
  }

   //7.釋放資源
   sqlSession.close();
   is.close();
}
  • 測試:給ids集合中增長1和2測試,而後再集合中增長3來測試,發現均可以

2.4 SQL片斷抽取

  • 咱們發如今映射文件中的sql語句,有不少都有重複的部分,那怎麼處理呢?

  • 經過sql片斷抽取:

 

 

  • Sql 中可將重複的 sql 提取出來,使用時用 include 引用便可,最終達到 sql 重用的目的

  • 代碼:

  • 映射文件:

<mapper namespace="com.itheima.mapper.StudentMapper">
<!--抽取-->
   <sql id="select" >SELECT * FROM student</sql>
   <select id="selectAll" resultType="student">
       <!--引用-->
       <include refid="select"/>
   </select>

   <select id="selectById" resultType="student" parameterType="int">
       <!--引用-->
       <include refid="select"/> WHERE id = #{id}
   </select>

   <insert id="insert" parameterType="student">
      INSERT INTO student VALUES (#{id},#{name},#{age})
   </insert>

   <update id="update" parameterType="student">
      UPDATE student SET name = #{name},age = #{age} WHERE id = #{id}
   </update>

   <delete id="delete" parameterType="int">
      DELETE FROM student WHERE id = #{id}
   </delete>

   <select id="selectCondition" resultType="student" parameterType="student">
       <!--引用-->
       <include refid="select"/>
       <where>
           <if test="id != null">
              id = #{id}
           </if>
           <if test="name != null">
              AND name = #{name}
           </if>
           <if test="age != null">
              AND age = #{age}
           </if>
       </where>
   </select>

   <select id="selectByIds" resultType="student" parameterType="list">
       <!--引用-->
       <include refid="select"/>
       <where>
           <foreach collection="list" open="id IN (" close=")" item="id" separator=",">
              #{id}
           </foreach>
       </where>
   </select>
</mapper>

2.5 知識小結

 

 

 

三. 分頁插件 ***

3.1 分頁插件介紹

  • 常見的分頁效果:例如百度:

 

 

  • 分頁能夠將不少條結果進行分頁顯示

  • 若是當前在第一頁,則沒有上一頁。若是當前在最後一頁,則沒有下一頁

  • 須要明確當前是第幾頁,這一頁中顯示多少條結果

  • MyBatis分頁插件總結

    • 在企業級開發中,分頁也是一種常見的技術

    • 而目前使用的 MyBatis 是不帶分頁功能的,若是想實現分頁的 功能,須要咱們手動編寫 LIMIT 語句

    • 可是不一樣的數據庫實現分頁的 SQL 語句也是不一樣的,因此手寫分頁 成本較高

    • 這個時候就能夠藉助分頁插件來幫助咱們實現分頁功能

    • PageHelper:第三方分頁助手。將複雜的分頁操做進行封裝,從而讓分頁功能變得很是簡單

3.2 分頁插件的使用

  • MyBatis可使用第三方的插件來對功能進行擴展,分頁助手PageHelper是將分頁的複雜操做進行封裝,使用簡單的方式便可得到分頁的相關數據

  • 開發步驟:

  • ①導入與PageHelper的jar包 「02-MyBatis進階\資料\分頁插件jar包」

  • ②在mybatis核心配置文件中配置PageHelper插件

<!-- 注意:分頁助手的插件,配置在typeAliases以後。interceptor:攔截器,插件都是以攔截器形式實現的 -->
<plugins>
       <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
  • ③測試:新建com.itheima.paging.Test01

package com.itheima.paging;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.itheima.bean.Student;
import com.itheima.mapper.StudentMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.InputStream;
import java.util.List;

public class Test01 {
   @Test
   public void selectPaging() throws Exception{
       //1.加載核心配置文件
       InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");

       //2.獲取SqlSession工廠對象
       SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

       //3.經過工廠對象獲取SqlSession對象
       SqlSession sqlSession = sqlSessionFactory.openSession(true);

       //4.獲取StudentMapper接口的實現類對象
       StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

       //經過分頁助手來實現分頁功能 startPage參數1:當前頁碼,參數2:每頁顯示幾條
       // 第一頁:顯示3條數據 pageNum,pageSize
       //PageHelper.startPage(1,3);
       // 第二頁:顯示3條數據
       //PageHelper.startPage(2,3);
       // 第三頁:顯示3條數據
       PageHelper.startPage(3,3);

       //5.調用實現類的方法,接收結果
       List<Student> list = mapper.selectAll();

       //6.處理結果
       for (Student student : list) {
           System.out.println(student);
      }
       //7.釋放資源
       sqlSession.close();
       is.close();
  }
}

3.3 分頁插件的參數獲取

  • PageInfo:封裝分頁相關參數的功能類

  • 核心方法:

 

 

  • 測試:修改Test01代碼,在釋放資源以前,增長以下代碼:

//其餘分頁的數據
PageInfo<User> pageInfo = new PageInfo<User>(list);
System.out.println("總條數:"+pageInfo.getTotal());
System.out.println("總頁數:"+pageInfo.getPages());
System.out.println("當前頁:"+pageInfo.getPageNum());
System.out.println("每頁顯示長度:"+pageInfo.getPageSize());
System.out.println("是否第一頁:"+pageInfo.isIsFirstPage());
System.out.println("是否最後一頁:"+pageInfo.isIsLastPage());

3.4 分頁插件知識小結

  • 分頁:能夠將不少條結果進行分頁顯示

  • 分頁插件 jar 包: pagehelper-5.1.10.jar 、 jsqlparser-3.1.jar

  • <plugins>:集成插件標籤

  • 分頁助手相關 API

    • PageHelper:分頁助手功能類:

      1. startPage():設置分頁參數

    • PageInfo:分頁相關參數功能類:

      1. getTotal():獲取總條數

      2. getPages():獲取總頁數

      3. getPageNum():獲取當前頁

      4. getPageSize():獲取每頁顯示條數

      5. getPrePage():獲取上一頁

      6. getNextPage():獲取下一頁

      7. isIsFirstPage():獲取是不是第一頁

      8. isIsLastPage():獲取是不是最後一頁

四.MyBatis的多表操做 ***

4.1 多表模型介紹

  • 咱們以前學習的都是基於單表操做的,而實際開發中,隨着業務難度的加深,確定須要多表操做的

  • 多表模型分類

    • 一對一:在任意一方創建外鍵,關聯對方的主鍵

    • 一對多:在多的一方創建外鍵,關聯一的一方的主鍵

    • 多對多:藉助中間表,中間表至少兩個字段,分別關聯兩張表的主鍵

4.2 多表模型一對一操做

  • 一對一模型: 人和身份證,一我的只有一個身份證

     

     

  • 代碼實現

    1. sql語句準備

      CREATE TABLE person(
      	id INT PRIMARY KEY AUTO_INCREMENT,
      	NAME VARCHAR(20),
      	age INT
      );
      INSERT INTO person VALUES (NULL,'張三',23);
      INSERT INTO person VALUES (NULL,'李四',24);
      INSERT INTO person VALUES (NULL,'王五',25);
      
      CREATE TABLE card(
      	id INT PRIMARY KEY AUTO_INCREMENT,
      	number VARCHAR(30),
      	pid INT,
      	CONSTRAINT cp_fk FOREIGN KEY (pid) REFERENCES person(id)
      );
      INSERT INTO card VALUES (NULL,'12345',1);
      INSERT INTO card VALUES (NULL,'23456',2);
      INSERT INTO card VALUES (NULL,'34567',3);
    • 老師在視頻中拖出這兩張表的關係圖以下:

       

       

    • 看到的怎麼是一對多呢?這是由於外鍵pid並無設置惟一約束,若是外鍵不是惟一,那就是容許重複,若是外鍵能夠重複,那就是一對多

    • 因此若是想看到1:1的效果,那就須要給pid增長一個約束unique

    1. 建立項目mybatis03

     

     

    • jdbc.properties

      driver=com.mysql.jdbc.Driver
      url=jdbc:mysql://192.168.59.143:3306/db2
      username=root
      password=itheima
    • MyBatisConfig.xml

      <?xml version="1.0" encoding="UTF-8" ?>
      <!--MyBatis的DTD約束-->
      <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
      
      <!--configuration 核心根標籤-->
      <configuration>
      
          <!--引入數據庫鏈接的配置文件-->
          <properties resource="jdbc.properties"/>
      
          <!--配置LOG4J-->
          <settings>
              <setting name="logImpl" value="log4j"/>
          </settings>
      
          <!--起別名-->
          <typeAliases>
              <package name="com.itheima.bean"/>
          </typeAliases>
      
          <!--environments配置數據庫環境,環境能夠有多個。default屬性指定使用的是哪一個-->
          <environments default="mysql">
              <!--environment配置數據庫環境  id屬性惟一標識-->
              <environment id="mysql">
                  <!-- transactionManager事務管理。  type屬性,採用JDBC默認的事務-->
                  <transactionManager type="JDBC"></transactionManager>
                  <!-- dataSource數據源信息   type屬性 鏈接池-->
                  <dataSource type="POOLED">
                      <!-- property獲取數據庫鏈接的配置信息 -->
                      <property name="driver" value="${driver}" />
                      <property name="url" value="${url}" />
                      <property name="username" value="${username}" />
                      <property name="password" value="${password}" />
                  </dataSource>
              </environment>
          </environments>
      
          <!-- mappers引入映射配置文件 -->
          <mappers>
          </mappers>
      </configuration>
    • log4j.properties

      # Global logging configuration
      # ERROR WARN INFO DEBUG
      log4j.rootLogger=DEBUG, stdout
      # Console output...
      log4j.appender.stdout=org.apache.log4j.ConsoleAppender
      log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
      log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
    1. javabean:card

      package com.itheima.bean;
      
      public class Card {
          private Integer id;     //主鍵id
          private String number;  //身份證號
      
          private Person p;       //所屬人的對象 *** 在表中是外鍵pid:人id,可是在javabean中通常都是外鍵對應的實體類javabean
      
          public Card() {
          }
      
          public Card(Integer id, String number, Person p) {
              this.id = id;
              this.number = number;
              this.p = p;
          }
      
          public Integer getId() {
              return id;
          }
      
          public void setId(Integer id) {
              this.id = id;
          }
      
          public String getNumber() {
              return number;
          }
      
          public void setNumber(String number) {
              this.number = number;
          }
      
          public Person getP() {
              return p;
          }
      
          public void setP(Person p) {
              this.p = p;
          }
      
          @Override
          public String toString() {
              return "Card{" +
                      "id=" + id +
                      ", number='" + number + '\'' +
                      ", p=" + p +
                      '}';
          }
      }
    1. javabean:person

      package com.itheima.bean;
      
      public class Person {
          private Integer id;     //主鍵id
          private String name;    //人的姓名
          private Integer age;    //人的年齡
      
          public Person() {
          }
      
          public Person(Integer id, String name, Integer age) {
              this.id = id;
              this.name = name;
              this.age = age;
          }
      
          public Integer getId() {
              return id;
          }
      
          public void setId(Integer id) {
              this.id = id;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public Integer getAge() {
              return age;
          }
      
          public void setAge(Integer age) {
              this.age = age;
          }
      
          @Override
          public String toString() {
              return "Person{" +
                      "id=" + id +
                      ", name='" + name + '\'' +
                      ", age=" + age +
                      '}';
          }
      }
    1. 配置文件:新建com.itheima.one_to_one.OneToOneMapper.xml

      <?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.itheima.table01.OneToOneMapper">
          <!--配置字段和實體對象屬性的映射關係
      	type指定要配置的實體對象是哪一個:card
      	-->
          <resultMap id="oneToOne" type="card">
              <!--id配置主鍵列:將sql中查詢的cid列與card實體類中的id進行關聯 -->
              <id column="cid" property="id" />
              <!--result配置非主鍵列-->
              <result column="number" property="number" />
              <!--
                  association:配置被包含對象的映射關係
                  property:被包含對象的變量名(屬性名,在Card實體類中有一個p屬性)
                  javaType:被包含對象的數據類型(直接給person別名,由於咱們經過typeAliases統一設置了bean包下全部實體類的別名了)
              -->
              <association property="p" javaType="person">
                  <id column="pid" property="id" />
                  <result column="name" property="name" />
                  <result column="age" property="age" />
              </association>
          </resultMap>
      	<!--resultMap屬性指定的是resultMap標籤的id
      	查詢出來的結果涉及到兩張表,因此不能使用resultType了
      	-->
          <select id="selectAll" resultMap="oneToOne">
              SELECT c.id cid,number,pid,NAME,age FROM card c,person p WHERE c.pid=p.id
          </select>
      </mapper>
    • 如何肯定誰包含了誰?哪一個是被包含對象?

    • 經過javabean的關聯屬性:

    • 在Card表中有一個關聯屬性P,那麼Card就包含了Person

    1. MyBatisConfig.xml中配置映射文件:

      <mappers>
          <mapper resource="com/itheima/one_to_one/OneToOneMapper.xml"/>
      </mappers>
    1. 接口com.itheima.table01.OneToOneMapper

      package com.itheima.table01;
      
      import com.itheima.bean.Card;
      
      import java.util.List;
      
      public interface OneToOneMapper {
          //查詢所有
          public abstract List<Card> selectAll();
      }
      
    1. 測試類:com.itheima.table01.Test01;

      package com.itheima.table01;
      
      import com.itheima.bean.Card;
      import org.apache.ibatis.io.Resources;
      import org.apache.ibatis.session.SqlSession;
      import org.apache.ibatis.session.SqlSessionFactory;
      import org.apache.ibatis.session.SqlSessionFactoryBuilder;
      import org.junit.Test;
      
      import java.io.InputStream;
      import java.util.List;
      
      public class Test01 {
          @Test
          public void selectAll() throws Exception{
              //1.加載核心配置文件
              InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
      
              //2.獲取SqlSession工廠對象
              SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
      
              //3.經過工廠對象獲取SqlSession對象
              SqlSession sqlSession = sqlSessionFactory.openSession(true);
      
              //4.獲取OneToOneMapper接口的實現類對象
              OneToOneMapper mapper = sqlSession.getMapper(OneToOneMapper.class);
      
              //5.調用實現類的方法,接收結果
              List<Card> list = mapper.selectAll();
      
              //6.處理結果
              for (Card c : list) {
                  System.out.println(c);
              }
      
              //7.釋放資源
              sqlSession.close();
              is.close();
          }
      }
    1. 結果:

       

       

  • 一對一配置總結:

<resultMap>:配置字段和對象屬性的映射關係標籤。
    id 屬性:惟一標識
    type 屬性:實體對象類型
<id>:配置主鍵映射關係標籤。
<result>:配置非主鍵映射關係標籤。
    column 屬性:表中字段名稱
    property 屬性: 實體對象變量名稱
<association>:配置被包含對象的映射關係標籤。
    property 屬性:被包含對象的變量名
    javaType 屬性:被包含對象的數據類型
  • 分析圖

     

     

4.3 多表模型一對多操做

  • 一對多模型: 一對多模型:班級和學生,一個班級能夠有多個學生

 

 

  • 代碼實現

    1. sql語句準備

      CREATE TABLE classes(
      	id INT PRIMARY KEY AUTO_INCREMENT,
      	NAME VARCHAR(20)
      );
      INSERT INTO classes VALUES (NULL,'黑馬一班');
      INSERT INTO classes VALUES (NULL,'黑馬二班');
      
      
      CREATE TABLE student(
      	id INT PRIMARY KEY AUTO_INCREMENT,
      	NAME VARCHAR(30),
      	age INT,
      	cid INT,
      	CONSTRAINT cs_fk FOREIGN KEY (cid) REFERENCES classes(id)
      );
      INSERT INTO student VALUES (NULL,'張三',23,1);
      INSERT INTO student VALUES (NULL,'李四',24,1);
      INSERT INTO student VALUES (NULL,'王五',25,2);
      INSERT INTO student VALUES (NULL,'趙六',26,2);
    1. 新建javabean:classes

      package com.itheima.bean;
      
      import java.util.List;
      
      public class Classes {
          private Integer id;     //主鍵id
          private String name;    //班級名稱
      
          private List<Student> students; //班級中全部學生對象*** 一個班級裏多個學生
      
          public Classes() {
          }
      
          public Classes(Integer id, String name, List<Student> students) {
              this.id = id;
              this.name = name;
              this.students = students;
          }
      
          public Integer getId() {
              return id;
          }
      
          public void setId(Integer id) {
              this.id = id;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public List<Student> getStudents() {
              return students;
          }
      
          public void setStudents(List<Student> students) {
              this.students = students;
          }
      
          @Override
          public String toString() {
              return "Classes{" +
                      "id=" + id +
                      ", name='" + name + '\'' +
                      ", students=" + students +
                      '}';
          }
      }
      
    1. javabean:student

      package com.itheima.bean;
      
      import java.util.List;
      
      public class Student {
          private Integer id;     //主鍵id
          private String name;    //學生姓名
          private Integer age;    //學生年齡
      
          public Student() {
          }
      
          public Student(Integer id, String name, Integer age) {
              this.id = id;
              this.name = name;
              this.age = age;
          }
      
          public Integer getId() {
              return id;
          }
      
          public void setId(Integer id) {
              this.id = id;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public Integer getAge() {
              return age;
          }
      
          public void setAge(Integer age) {
              this.age = age;
          }
      
          @Override
          public String toString() {
              return "Student{" +
                      "id=" + id +
                      ", name='" + name + '\'' +
                      ", age=" + age +
                      '}';
          }
      }
      
    1. 配置文件:com.itheima.one_to_many.OneToManyMapper.xml

      <?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.itheima.table02.OneToManyMapper">
          <resultMap id="oneToMany" type="classes">
              <id column="cid" property="id"/>
              <result column="cname" property="name"/>
      
              <!--
                  collection:配置被包含的集合對象映射關係(若是被包含的對象是多的一方,須要用collection)
                  property:被包含對象的變量名
                  ofType:被包含對象的實際數據類型(collection標籤中指定被包含對象類型用的是ofType)
              -->
              <collection property="students" ofType="student">
                  <id column="sid" property="id"/>
                  <result column="sname" property="name"/>
                  <result column="sage" property="age"/>
              </collection>
          </resultMap>
          <select id="selectAll" resultMap="oneToMany">
              SELECT c.id cid,c.name cname,s.id sid,s.name sname,s.age sage FROM classes c,student s WHERE c.id=s.cid
          </select>
      </mapper>
    1. 配置映射文件

       <mappers>
           <mapper resource="com/itheima/one_to_one/OneToOneMapper.xml"/>
           <mapper resource="com/itheima/one_to_many/OneToManyMapper.xml"/>
      </mappers>
    1. 接口

      package com.itheima.table02;
      
      import com.itheima.bean.Classes;
      
      import java.util.List;
      
      public interface OneToManyMapper {
          //查詢所有
          public abstract List<Classes> selectAll();
      }
      
    1. 測試類com.itheima.table02.Test01

      package com.itheima.table02;
      
      import com.itheima.bean.Classes;
      import com.itheima.bean.Student;
      import org.apache.ibatis.io.Resources;
      import org.apache.ibatis.session.SqlSession;
      import org.apache.ibatis.session.SqlSessionFactory;
      import org.apache.ibatis.session.SqlSessionFactoryBuilder;
      import org.junit.Test;
      
      import java.io.InputStream;
      import java.util.List;
      
      public class Test01 {
          @Test
          public void selectAll() throws Exception{
              //1.加載核心配置文件
              InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
      
              //2.獲取SqlSession工廠對象
              SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
      
              //3.經過工廠對象獲取SqlSession對象
              SqlSession sqlSession = sqlSessionFactory.openSession(true);
      
              //4.獲取OneToManyMapper接口的實現類對象
              OneToManyMapper mapper = sqlSession.getMapper(OneToManyMapper.class);
      
              //5.調用實現類的方法,接收結果
              List<Classes> classes = mapper.selectAll();
      
              //6.處理結果
              for (Classes cls : classes) {
                  System.out.println(cls.getId() + "," + cls.getName());
                  List<Student> students = cls.getStudents();
                  for (Student student : students) {
                      System.out.println("\t" + student);
                  }
              }
      
              //7.釋放資源
              sqlSession.close();
              is.close();
          }
      }
    1. 結果:

       

       

  • 一對多配置文件總結:

<resultMap>:配置字段和對象屬性的映射關係標籤。
    id 屬性:惟一標識
    type 屬性:實體對象類型
<id>:配置主鍵映射關係標籤。
<result>:配置非主鍵映射關係標籤。
    column 屬性:表中字段名稱
    property 屬性: 實體對象變量名稱
<collection>:配置被包含集合對象的映射關係標籤。
    property 屬性:被包含集合對象的變量名
    ofType 屬性:集合中保存的對象數據類型
  • 分析圖:

     

     

4.4 多表模型多對多操做

  • 多對多模型:學生和課程,一個學生能夠選擇多門課程、一個課程也能夠被多個學生所選擇

 

 

  • 代碼實現

    1. sql語句準備

      CREATE TABLE course(
      	id INT PRIMARY KEY AUTO_INCREMENT,
      	NAME VARCHAR(20)
      );
      INSERT INTO course VALUES (NULL,'語文');
      INSERT INTO course VALUES (NULL,'數學');
      
      
      CREATE TABLE stu_cr(
      	id INT PRIMARY KEY AUTO_INCREMENT,
      	sid INT,
      	cid INT,
      	CONSTRAINT sc_fk1 FOREIGN KEY (sid) REFERENCES student(id),
      	CONSTRAINT sc_fk2 FOREIGN KEY (cid) REFERENCES course(id)
      );
      INSERT INTO stu_cr VALUES (NULL,1,1);
      INSERT INTO stu_cr VALUES (NULL,1,2);
      INSERT INTO stu_cr VALUES (NULL,2,1);
      INSERT INTO stu_cr VALUES (NULL,2,2);
    1. Javabean

      package com.itheima.bean;
      
      public class Course {
          private Integer id;     //主鍵id
          private String name;    //課程名稱
      
          public Course() {
          }
      
          public Course(Integer id, String name) {
              this.id = id;
              this.name = name;
          }
      
          public Integer getId() {
              return id;
          }
      
          public void setId(Integer id) {
              this.id = id;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          @Override
          public String toString() {
              return "Course{" +
                      "id=" + id +
                      ", name='" + name + '\'' +
                      '}';
          }
      }
    1. 修改:Student

       private List<Course> courses;   // 學生所選擇的課程集合
        public Student(Integer id, String name, Integer age, List<Course> courses) {
              this.id = id;
              this.name = name;
              this.age = age;
              this.courses = courses;
          }
           public List<Course> getCourses() {
              return courses;
          }
      
          public void setCourses(List<Course> courses) {
              this.courses = courses;
          }
    2. 咱們這裏只是多表查詢,不作其餘操做,因此中間表不須要對應的實體類

    3. 配置文件

      <?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.itheima.table03.ManyToManyMapper">
          <resultMap id="manyToMany" type="student">
              <id column="sid" property="id"/>
              <result column="sname" property="name"/>
              <result column="sage" property="age"/>
      
              <collection property="courses" ofType="course">
                  <id column="cid" property="id"/>
                  <result column="cname" property="name"/>
              </collection>
          </resultMap>
          <select id="selectAll" resultMap="manyToMany">
              SELECT sc.sid,s.name sname,s.age sage,sc.cid,c.name cname FROM student s,course c,stu_cr sc WHERE sc.sid=s.id AND sc.cid=c.id
          </select>
          <!--注意這裏查詢的是sc.cid,將這個cid給course的id了,這也是能夠的,由於都是課程id
      		但其實sql語句中的sc.cid,能夠換成c.id,這樣的話給course的id更合適	
      	-->
      </mapper>
    1. 配置

       <mappers>
              <mapper resource="com/itheima/one_to_one/OneToOneMapper.xml"/>
              <mapper resource="com/itheima/one_to_many/OneToManyMapper.xml"/>
              <mapper resource="com/itheima/many_to_many/ManyToManyMapper.xml"/>
          </mappers>
    1. 接口

      package com.itheima.table03;
      
      import com.itheima.bean.Student;
      
      import java.util.List;
      
      public interface ManyToManyMapper {
          //查詢所有
          public abstract List<Student> selectAll();
      }
      
    1. 測試類

      package com.itheima.table03;
      
      import com.itheima.bean.Course;
      import com.itheima.bean.Student;
      import org.apache.ibatis.io.Resources;
      import org.apache.ibatis.session.SqlSession;
      import org.apache.ibatis.session.SqlSessionFactory;
      import org.apache.ibatis.session.SqlSessionFactoryBuilder;
      import org.junit.Test;
      
      import java.io.InputStream;
      import java.util.List;
      
      public class Test01 {
          @Test
          public void selectAll() throws Exception{
              //1.加載核心配置文件
              InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
      
              //2.獲取SqlSession工廠對象
              SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
      
              //3.經過工廠對象獲取SqlSession對象
              SqlSession sqlSession = sqlSessionFactory.openSession(true);
      
              //4.獲取ManyToManyMapper接口的實現類對象
              ManyToManyMapper mapper = sqlSession.getMapper(ManyToManyMapper.class);
      
              //5.調用實現類的方法,接收結果
              List<Student> students = mapper.selectAll();
      
              //6.處理結果
              for (Student student : students) {
                  System.out.println(student.getId() + "," + student.getName() + "," + student.getAge());
                  List<Course> courses = student.getCourses();
                  for (Course cours : courses) {
                      System.out.println("\t" + cours);
                  }
              }
      
              //7.釋放資源
              sqlSession.close();
              is.close();
          }
      }
    1. 結果

       

       

  • 多對多配置文件總結:

<resultMap>:配置字段和對象屬性的映射關係標籤。
	id 屬性:惟一標識
	type 屬性:實體對象類型
 <id>:配置主鍵映射關係標籤。
 <result>:配置非主鍵映射關係標籤。
	column 屬性:表中字段名稱
	property 屬性: 實體對象變量名稱
<collection>:配置被包含集合對象的映射關係標籤。
	property 屬性:被包含集合對象的變量名
	ofType 屬性:集合中保存的對象數據類型
  • 分析圖

     

     

4.5 多表模型操做總結

 

相關文章
相關標籤/搜索