• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • 動態SQL和多表關聯-筆記

    標簽: Mybatis

    《動態SQL與多表關聯》筆記

    學習目標

    1. 能夠使用動態SQL完成SQL拼接
    2. 能夠使用resultMap完成多表查詢
    3. 能夠使用一對一查詢
    4. 能夠使用一對多查詢 (注:多對多其實就是兩個一個多)

    映射文件:為什么要resultMap

    目標

    1. 定義結果映射

    2. 使用結果映射

    回顧

    在mybatis中有2種配置文件:

    1. 核心配置文件,如:sqlMapConfig.xml
    2. 實體類映射文件,如:UserMapper.xml

    實體類映射文件2個功能:

    1. 編寫SQL語句
    2. 指定實體類與表之間映射關系

    第2個功能還沒用到,如果一張表中所有的列名與實體類中屬性名全部相同,就不需要映射。

    在這里插入圖片描述

    如果表中列名與實體類中屬性名有不同,必須要映射,否則這列的數據就無法封裝。

    步驟

    修改表結構

    -- 復制user為user2新表,新復制的表沒有主鍵約束,沒有自增
    create table user2 select * from user;
    
    -- 添加主鍵約束
    alter table user2 add primary key (id);
    
    -- 增加自增功能
    alter table user2 modify id int auto_increment;
    
    -- 從100開始自增
    alter table user2 auto_increment = 100;
    
    -- 修改用戶表結構,將用戶名字段由username改成user_name
    alter table user2 change username user_name varchar(20);
    
    select * from user2;
    

    查詢結果如下

    在這里插入圖片描述

    復制idea原來項目

    1. 在windows下復制原來的項目整個目錄,并且改名。
      在這里插入圖片描述

    2. 修改項目中的文件名,項目的描述文件
      在這里插入圖片描述

    3. 在idea中導入項目

    在這里插入圖片描述

    1. 選擇上面修改過的文件

    在這里插入圖片描述

    1. 如果使用idea插件,每次只能開一個mybatis項目,不然有時會發現DAO接口和XML映射文件有報錯

    2. 刪除UserMapper接口中所有的方法,刪除UserMapper.xml中所有的配置,刪除測試中所有測試的方法

    數據庫名字要修改

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/day26
    jdbc.username=root
    jdbc.password=root
    

    用戶實體類不變

    package com.itheima.entity;
    
    import java.sql.Date;
    
    /**
     用戶實體類對象 */
    public class User {
    
        private Integer id;   //注:使用大寫
        private String username;
        private Date birthday;
        private String sex;
        private String address;
    
        public User() {
        }
    
        public User(Integer id, String username, Date birthday, String sex, String address) {
            this.id = id;
            this.username = username;
            this.birthday = birthday;
            this.sex = sex;
            this.address = address;
        }
    
    	 //get和set省略
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", username='" + username + '\'' +
                    ", birthday=" + birthday +
                    ", sex='" + sex + '\'' +
                    ", address='" + address + '\'' +
                    '}';
        }
    }
    

    UserMapper接口

    User findUser2ById(Integer id);
    

    映射文件

    <?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.dao.UserMapper">
    
        <!--查詢user2的表-->
        <select id="findUser2ById" resultType="user">
            select id,user_name as username,birthday,sex,address from user2 where id=#{id}
        </select>
    </mapper>
    

    結果如下

    配置前:

    在這里插入圖片描述

    解決方法:

    1. 使用別名,給user_name定義別名,別名名字與username相同

      select id,user_name as username,birthday,sex,address from user2 where id=#{id}
      
    2. resultMap來實現實體類與表中列映射

    映射文件:resultMap輸出類型

    使用resultMap實現

    說明:resultMap用于配置sql語句中字段(列)的名稱,與java對象中屬性名稱的對應關系。本質上還是要把執行結果映射到java對象上。分兩步:

    1. 使用resultMap來定義一個映射關系,并且給這個映射id的屬性,這個id在同一個配置文件中要唯一

    2. 在查詢的時候,將查詢的結果設置為上面的映射,通過id來引用

    配置mapper映射文件

    1. 定義映射,指定id和type,type為實體類的別名
    2. id標簽:映射主鍵字段,如果列名與屬性名相同可以省略
    3. result標簽:映射普通字段,指定哪個屬性對應哪個列,這里只需映射username即可
    4. 在查詢的結果中使用resultMap,為上面的映射id
    <?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.dao.UserMapper">
    
        <!--
        1. 使用resultMap來定義一個映射關系
        id:給這個映射唯一標識
        type:對應的實體類的類型
        -->
        <resultMap id="userMap2" type="user">
            <!--
            id子元素:用于指定主鍵映射(如果列名與屬性名相同,可以不映射)
            屬性:
                column 指定表中列名
                property 指定實體體中屬性名
                javaType 指定屬性名的數據類型
            result:子元素用于定義其它列的映射,兩個屬性與上面含義相同,只映射不同的列
            -->
            <id column="id" property="id"/>
            <result column="user_name" property="username"/>
        </resultMap>
    
        <!--
        2. 查詢user2的表的時候,通過id引用上面的映射關系
        resultType 直接指定實體類的別名
        resultMap 指定定義的映射關系
         -->
        <select id="findUser2ById" resultMap="userMap2">
            select id,user_name,birthday,sex,address from user2 where id=#{id}
        </select>
    </mapper>
    

    測試

    查詢id為1的用戶

    @Test
    public void testFindUser2ById() {
        User user = userMapper.findUser2ById(1);
        System.out.println(user);
    }
    

    執行結果

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-m8GVqcaQ-1592726289127)(assets/image-20200516094550680.png)]

    映射流程

    在這里插入圖片描述

    映射文件的標簽小結

    標簽 子標簽 說明
    <resultMap> 定義表的字段名與實體類的屬性名之間映射關系
    <id> 定義主鍵列
    <result> 定義其它列

    創建會話的工具類

    目標

    創建會話的工具類

    需求

    因為以后每天都需要使用會話對象,如果每次都完整的寫一次,比較麻煩。創建一個工具類,調用一個方法獲取會話對象。

    步驟

    1. 在靜態代碼塊中創建會話工廠
    2. 編寫靜態方法得到會話

    代碼

    package com.itheima.utils;
    
    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;
    
    /**
     * 創建會話的工具類
     */
    public class SqlSessionUtils {
    
        private static SqlSessionFactory factory;
    
        /**
         * 在靜態代碼塊中創建會話工廠
         */
        static {
            //0.創建核心配置文件的輸入流
            try (InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml")) {
                //1.創建工廠建造類
                SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
                //2.創建會話工廠,讀取核心配置文件
                factory = factoryBuilder.build(inputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 編寫一個靜態方法獲取會話
         */
        public static SqlSession getSession() {
            return factory.openSession();
        }
    
    }
    

    動態SQL:環境搭建

    目標

    1. 學習哪些動態SQL標簽
    2. 復制項目

    MyBatis動態SQL

    以前:我們的SQL語句都是直接寫死在配置文件中,一但寫好了就固定了。

    概念:在代碼的執行過程中,根據代碼的執行情況動態拼接成不同的SQL語句

    將要學習的標簽:類似于JSTL中標簽

    1. if 在XML中進行判斷,如果符合條件就進行拼接
    2. where 類似于sql where語句
    3. set 用于更新的操作
    4. foreach 對集合或數組進行遍歷
    5. sql 定義一個SQL代碼片段
    6. include 引用上面代碼片段

    需求

    1. 根據用戶名稱和性別查詢用戶數據
    2. 姓名是模糊查詢
    3. 查詢User表

    聲明UserMapper接口方法

    1. 根據用戶名稱和性別查詢用戶
    2. 參數是User對象
    /**
     * 根據用戶名稱和性別查詢用戶
     */
    List<User> findUserByNameAndSex(User user);
    

    配置mappr映射文件

    <!--根據用戶名稱和性別查詢用戶-->
    <select id="findUserByNameAndSex" resultType="user">
        select * from user where username like "%"#{username}"%" and sex = #{sex}
    </select>
    

    執行效果

    在這里插入圖片描述

    測試

    @Test測試方法中通過用戶名和性別查詢多個用戶,查詢條件是"精"和"女"

    @Test
    public void testFindUserByNameAndSex() {
        //封裝查詢條件
        User user = new User();
        user.setUsername("精");
        user.setSex("女");
        List<User> users = userMapper.findUserByNameAndSex(user);
        System.out.println(users);
    }
    

    動態SQL:if和where標簽

    目標

    1. 動態SQL語句if標簽的使用
    2. 動態SQL語句where標簽的使用

    應用場景

    如果使用一個實體類來封裝所有的查詢條件,如果這個實體類屬性有值,則參與查詢,否則就不做為查詢條件。

    在這里插入圖片描述

    if標簽

    作用

    判斷某個條件是否為真,如果為真則拼接標簽體中的SQL語句

    UserMapper.xml

    1. 根據用戶名稱和性別查詢用戶
    2. if:判斷用戶名稱不為空,且不為空字符串,則作為查詢條件
    3. if:判斷用戶性別不為空,且不為空字符串,則作為查詢條件
    <!--
    根據用戶名稱和性別查詢用戶
    if 標簽的作用:判斷某個條件是否為真,如果為真則拼接標簽體中的SQL語句
    -->
    <select id="findUserByNameAndSex" resultType="user">
        select * from user where
        <if test="username!=null and username!=''">
            username like "%"#{username}"%"
        </if>
        <if test="sex!=null and sex!=''">
            and sex = #{sex}
        </if>
    </select>
    

    測試代碼

    1. 通過用戶名和性別查詢多個用戶
    2. 同時設置名字和性別
    3. 只設置名字或只設置性別
    4. 名字和性別一個都不設置
    @Test
    public void testFindUserByNameAndSex() {
        //封裝查詢條件
        User user = new User();
        user.setUsername("精");
        user.setSex("女");
        List<User> users = userMapper.findUserByNameAndSex(user);
        System.out.println(users);
    }
    

    疑問:if標簽如果第1個條件沒有,會出現什么情況?如何解決這個問題?

    如果單獨使用if標簽,有時會出現問題,因為拼接的SQL語句是不正確的
    

    where標簽

    作用

    1. 相當于where關鍵字,在SQL語句中可以省略where關鍵字
    2. 根據拼接SQL字符串的情況,自動去掉多余的and, or , where關鍵字

    需求

    1. 只查性別
    2. 同時查姓名和性別
    3. 一個條件都不查

    UserMapper.xml

    1. 根據用戶名稱和性別查詢用戶
    2. if標簽寫在where標簽內部
      1. if:判斷用戶名稱不為空,且不為空字符串,則作為查詢條件
      2. if:判斷用戶性別不為空,且不為空字符串,則作為查詢條件
    <select id="findUserByNameAndSex" resultType="user">
        select * from user
        <where>
            <if test="username!=null and username!=''">
                username like "%"#{username}"%"
            </if>
            <if test="sex!=null and sex!=''">
                and sex = #{sex}
            </if>
        </where>
    </select>
    

    小結

    1. if標簽的作用:如果判斷條件為真,就拼接if標簽體中的SQL語句
    2. where標簽的作用:
      1. 相當于where關鍵字
      2. 去掉多余的and, or, where關鍵字

    動態SQL:set標簽

    目標

    set標簽的使用

    作用

    用于update標簽

    1. 相當于update中set關鍵字
    2. 同時修改多個字段,字段之間使用逗號分隔。可能拼接的時候會出現多余的逗號,set標簽可以去掉多余的逗號

    應用場景

    更新用戶信息的時候,有些實體類的屬性為空,為空就不更新,不為空才更新這個字段。

    在這里插入圖片描述

    需求

    動態修改用戶數據

    1. 如果username屬性不為空,則更新這個字段。
    2. 如果sex不為空則更新這個字段

    效果

    在這里插入圖片描述

    聲明mapper接口方法

    編寫更新用戶的方法,參數是user對象

    /**
     * 修改姓名和性別
     */
    int updateUser(User user);
    

    配置mapper映射文件

    通過id來更新用戶名或性別

    1. update標簽更新用戶數據
    2. 如果username不為空而且不為空串,則更新
    3. 如果sex不為空而且不為空串,則更新
    4. 最后加上where條件

    注:每個更新的字段后面都加上了逗號

    <!--
    1. 如果username屬性不為空,則更新這個字段。
    2. 如果sex不為空則更新這個字段
    -->
    <update id="updateUser">
        update user
        <set>
            <if test="username!=null and username!=''">
                username=#{username},
            </if>
            <if test="sex!=null and sex!=''">
                sex=#{sex}
            </if>
        </set>
        where id=#{id}
    </update>
    

    測試

    @Test
    public void testUpdateUser() {
        //封裝實體對象
        User user = new User();
        user.setUsername("黑熊精");
        user.setSex("男");
        user.setId(8);
        //調用方法
        int row = userMapper.updateUser(user);
        System.out.println("更新了" + row + "行記錄");
    }
    

    小結

    set標簽的作用是?

    1. 相當于更新語句中set關鍵字
    2. 可以去掉多余的逗號

    foreach標簽:參數類型是集合

    目標

    foreach標簽的使用:參數類型是集合的情況

    作用

    遍歷集合或數組,將集合或數組中每個元素都做為SQL語句的一部分進行拼接,拼接多次

    需求

    使用list集合封裝多個User對象,添加到數據庫中。

    聲明mapper接口方法

    提問:一條insert語句插入多條記錄的MySQL語句如何編寫?

    insert into 表名 values (全部列名),(全部列名),(全部列名)
    

    批量添加用戶的方法

    1. 參數是List,包含多個User對象
    int addUsers(List<User> users);
    

    配置mapper映射文件

    UserMapper.xml

    批量新增用戶,參數類型是:list

    <!--使用foreach標簽遍歷一個集合,生成SQL語句-->
    <insert id="addUsers">
        insert into user (username, birthday, sex, address) values
        <!--
        foreach標簽的屬性:
        collection 指定是集合還是數組,如果是集合使用list,如果是數組使用array
        item 表示集合中每個元素的變量名,這里是一個實體類對象
        separator 每次拼接完以后,添加1個符號分隔
        -->
        <foreach collection="list" item="user" separator=",">
            (#{user.username},#{user.birthday},#{user.sex},#{user.address})
        </foreach>
    </insert>
    

    測試

    1. 創建ArrayList,每個元素是User
    2. 調用方法添加多條記錄
    /**
     * 添加多個用戶
     */
    @Test
    public void testAddUsers() {
        //創建一個List集合,添加3個元素
        List<User> users = new ArrayList<>();
        users.add(new User(null,"牛魔王", Date.valueOf("1980-01-30"),"男","火焰山"));
        users.add(new User(null,"紅孩兒", Date.valueOf("2009-05-08"),"男","火云洞"));
        users.add(new User(null,"玉面狐貍", Date.valueOf("2005-11-01"),"女","狐貍洞"));
        int row = userMapper.addUsers(users);
        System.out.println("添加了" + row + "行記錄");
    }
    

    結果

    在這里插入圖片描述

    小結

    foreach標簽的屬性 作用:用于遍歷集合或數組,多次拼接生成SQL語句
    collection 取值:如果是集合使用list,如果是數組使用array
    item 代表集合中每個元素,給元素定義一個名字
    separator 每次遍歷完成以后添加1個分隔符
    #{變量名.屬性} 標簽體中引用的時候,必須使用變量名.屬性名

    foreach標簽:參數類型是數組

    目標

    foreach標簽:參數類型是數組

    需求

    實現批量刪除用戶

    分析

    刪除多條記錄的SQL語句如何編寫?

    delete from 表名 where id in (1,3,5)
    

    聲明mapper接口方法

    /**
     批量刪除用戶
     */
    int deleteUsers(int[] ids);
    

    配置mapper映射文件

    foreach標簽

    • 注:parameterType 因為內置別名中沒有數組類型的參數,所以當參數傳遞的是list和數組,都寫成list

    UserMapper.xml

    <!--批量刪除用戶 -->
    <delete id="deleteUsers">
        delete from user where id in
        <!--
        collection: 表示要遍歷的集合類型,數組使用array
        item: 表示其中每個元素的變量名
        open:表示循環開始前添加一個符號,只會執行1次
        separator 每次拼接完以后,添加1個符號分隔,執行多次
        close:表示循環結果以后添加一個符號,只會執行1次
        -->
        <foreach collection="array" open="(" item="id" separator="," close=")">
            #{id}
        </foreach>
    </delete>
    

    測試代碼

    1. 刪除多個用戶
    2. 返回影響的行數
    //刪除多個用戶
    @Test
    public void testDeleteUsers() {
        int [] ids = {2,4,6};
        int row = userMapper.deleteUsers(ids);
        System.out.println("刪除了" + row + "條記錄");
    }
    

    結果

    在這里插入圖片描述

    小結

    foreach標簽中的屬性 說明
    collection 如果遍歷數組,取值是array
    open 遍歷開始前添加1次符號
    close 遍歷結束后添加1次符號
    item 每次元素的變量名,通過#{變量名}來引用
    separator 每次遍歷的時候添加分隔符

    sql和include標簽

    目標

    學習sql和include標簽的作用

    作用

    1. sql標簽:定義一個SQL語句代碼段,并且使用id設置唯一的標識
    2. include標簽:包含上面定義的語句代碼段

    這2個標簽是要配合使用的,對定義的SQL代碼段進行重用

    需求

    應用場景:以前講過分頁的操作,至少要查詢2條SQL語句

    1. 這一頁的數據,同時滿足生日在這個范圍之類
    2. 總共有多少條記錄,同時滿足生日在這個范圍之類

    如果有多條SQL語句,它后面的where查詢條件是一樣的,我們就可以將這個查詢條件定義成一個代碼片段進行重用。

    在這里插入圖片描述

    1. 通過生日最小值,最大值的區間,組合查詢多個用戶。
    select * from user where 條件
    
    1. 使用相同的查詢條件,查詢一共有多少條記錄。
    select count(*) from user where 條件
    

    上面兩條語句where后面的條件是一樣的,可以考慮重用。

    步驟

    1. 使用Map封裝上面的條件: minDate,maxDate
    2. 在UserMapper.xml中使用sql標簽定義查詢條件代碼塊
    3. 在查詢方法中,使用include引用上面的條件代碼塊
    4. 查詢符合條件的用戶信息,返回List<User>
    5. 查詢符合條件的記錄數,返回int
    • 注:關于大于號小于號的處理。可以使用<(小于),>(大于)或者使用CDATA

    UserMapper接口

    /**
     * 查詢滿足條件的所有用戶
     * Map封裝多個查詢條件
     */
    List<User> findUsersByMap(Map<String, String> map);
    
    /**
     * 查詢滿足條件的記錄有多少條
     */
    int findCountByMap(Map<String, String> map);
    

    UserMapper.xml

    <!--
    1. sql標簽定義查詢條件代碼塊
        Map = {minDate='1999-9-9', maxDate='2000-1-1'}
        在XML中<或>符號是有特殊含義的,通常不能直接寫在XML中
        有兩種解決方案:
        1) 使用轉義:&lt; &gt;
        2) 使用CDATA包裹起來的內容表示純文本內容,XML解析器不對它進行解析
     -->
    <sql id="sqlCondition">
        <where>
            <if test="minDate!=null and minDate!=''">
                birthday >= #{minDate}
            </if>
            <if test="maxDate!=null and maxDate!=''">
                <![CDATA[
                  and birthday <= #{maxDate}
                ]]>
            </if>
        </where>
    </sql>
    
    <!--
    include標簽的作用:引用使用sql標簽定義的代碼段
       屬性:refid對應上面sql的id值
    -->
    <select id="findUsersByMap" resultType="user">
        select * from user  <include refid="sqlCondition"/>
    </select>
    
    <select id="findCountByMap" resultType="int">
        select count(*) from user <include refid="sqlCondition"/>
    </select>
    

    測試代碼

    @Test
    public void testFindUsersByMap() {
        HashMap<String, String> map = new HashMap<>();
        map.put("minDate","1980-01-01");
        map.put("maxDate", "1984-01-01");
        List<User> users = userMapper.findUsersByMap(map);
        users.forEach(System.out::println);
    }
    
    @Test
    public void testFindCountByMap() {
        HashMap<String, String> map = new HashMap<>();
        map.put("minDate","1980-01-01");
        map.put("maxDate", "1984-01-01");
        int count = userMapper.findCountByMap(map);
        System.out.println("滿足條件的有" + count + "條記錄");
    }
    

    小結

    1. sql標簽的作用:定義SQL語句的代碼段

      id屬性:定義代碼塊的標識

    2. include標簽的作用:引用上面代碼段

      refid屬性:引用上面的id的值

    多表關聯:搭建環境

    回顧:多表關系分類

    一對一關聯關系

    人和身份證的關系。一個人只能有一張身份證,一張身份證只能屬于一個人。雙向【一對一】關聯關系。

    一對多關聯關系

    舉一個例子:用戶和訂單的關系,部門和員工

    一個用戶可以有多個訂單,從用戶到訂單是【一對多】關聯關系。

    一個訂單只能屬于一個人,從訂單到人是【一對一】的關聯關系。

    多對多關聯系統

    舉個例子:學生和課程 多對多的關系

    一個學生可以選擇多門課程

    一門課程也可以由多個學生去選擇

    創建中間表,中間表與其它兩張表是一對多的關系,所以多對多本質上還是一對多的關系。

    一對一關系表結構

    用戶基本表與用戶信息表的關系

    一對一創建表的兩種方式:

    1. 從表外鍵設置唯一約束,特殊的1對多的關系
    2. 從表的主鍵又是外鍵,因為主鍵不能重復,所以外鍵也不重復

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Yob9TccG-1592726289135)(assets/1558318491379.png)]

    用戶表與用戶擴展信息表的代碼

    drop table if exists user;
    
    -- 創建用戶基本表
    create table user (
      id int primary key auto_increment,
      username varchar(20) not null,
      birthday date,
      sex char(1) default '男',
      address varchar(50)
    );
    
    insert into user values (null, '孫悟空','1980-10-24','男','花果山水簾洞');
    insert into user values (null, '白骨精','1992-11-12','女','白虎嶺白骨洞');
    insert into user values (null, '豬八戒','1983-05-20','男','福臨山云棧洞');
    insert into user values (null, '蜘蛛精','1995-03-22','女','盤絲洞');
     
     select * from user; 
     -- 用戶擴展信息表,一個用戶對應一條用戶擴展信息
     create table user_info (
        id int primary key,   -- 既是主鍵又是外鍵
        height double,  -- 身高厘米
        weight double,   -- 體重公斤
        married tinyint,    -- 是否結婚,1為結婚,0為未婚
        foreign key (id) references user(id)
     );
     
     -- 插入用戶擴展信息表
    insert into user_info values(1,185,90,1),(2,170,60,0);
    select * from user_info;
    

    創建工程

    在這里插入圖片描述

    類之間的關系

    如何體現對象與對象之間的一對一的關系呢?

    在User類中有一個UserInfo的屬性,反之,一個UserInfo類中包含了一個User的屬性
    

    在這里插入圖片描述

    在UserInfo類中創建User,創建一對一的關系

    package com.itheima.entity;
    
    /**
     * 用戶擴展信息對象
     */
    public class UserInfo {
    
        private Integer id;
        private Double height;
        private Double weight;
        private Boolean married;
    
        private User user;  //體現1對1的關系
    
        @Override
        public String toString() {
            return "UserInfo{" +
                    "id=" + id +
                    ", height=" + height +
                    ", weight=" + weight +
                    ", married=" + married +
                    '}';
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public Double getHeight() {
            return height;
        }
    
        public void setHeight(Double height) {
            this.height = height;
        }
    
        public Double getWeight() {
            return weight;
        }
    
        public void setWeight(Double weight) {
            this.weight = weight;
        }
    
        public Boolean getMarried() {
            return married;
        }
    
        public void setMarried(Boolean married) {
            this.married = married;
        }
    
        public User getUser() {
            return user;
        }
    
        public void setUser(User user) {
            this.user = user;
        }
    }
    
    

    在User類中創建UserInfo,創建一對一的關系

    package com.itheima.entity;
    
    import java.sql.Date;
    
    /**
     * 用戶實體類
     */
    public class User {
    
        private Integer id;
        private String username;
        private Date birthday;
        private String sex;
        private String address;
    
        //體現一對一的關系
        private UserInfo userInfo;
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", username='" + username + '\'' +
                    ", birthday=" + birthday +
                    ", sex='" + sex + '\'' +
                    ", address='" + address + '\'' +
                    '}';
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public Date getBirthday() {
            return birthday;
        }
    
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        public UserInfo getUserInfo() {
            return userInfo;
        }
    
        public void setUserInfo(UserInfo userInfo) {
            this.userInfo = userInfo;
        }
    }
    
    

    sqlMapConfig.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    
        <!--定義實體類別名-->
        <typeAliases>
            <package name="com.itheima.entity"/>
        </typeAliases>
    
        <environments default="default">
            <!--環境變量-->
            <environment id="default">
                <!--事務管理器-->
                <transactionManager type="JDBC"/>
                <!--數據源-->
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/day26"/>
                    <property name="username" value="root"/>
                    <property name="password" value="root"/>
                </dataSource>
            </environment>
        </environments>
    
        <!--加載其它映射文件-->
        <mappers>
            <package name="com.itheima.dao"/>
        </mappers>
    </configuration>
    

    mybatis插件的安裝

    1. 注:壓縮包不要解壓

    2. 在這里插入圖片描述

    3. 重啟idea

    在這里插入圖片描述

    多表關聯:一對一關聯

    目標

    在mybatis中實現一對一的關聯

    需求:查詢1號用戶和他的擴展信息

    編寫關聯查詢sql語句

    select * from user u inner join user_info i on u.id = i.id where u.id = 1
    

    查詢結果

    UserMapper接口

    編寫方法通過uid查找用戶和信息

    /**
      通過uid查找用戶和擴展信息
     */
    User findUserAndInfo(int id);
    

    association標簽

    作用:創建1對1的關聯關系

    • 用戶表是A
    • 擴展表是B
    • 關聯是A+B
    • 查詢結果是A+B

    在這里插入圖片描述

    UserMapper.xml的配置

    1. 定義User的映射userMap,包含主鍵和所有的屬性,無論屬性名與列名是否相同。

    2. 定義用戶信息的映射userInfoMap,包含主鍵和所有的屬性,無論屬性名與列名是否相同。

    3. 定義映射userAndInfoMap,extends繼承于userMap,同時必須指定type屬性。

    4. 使用association定義一對一關聯映射,指定:property、resultMap屬性,將resultMap指定為userInfoMap。

    5. 使用表連接查詢:通過用戶id查詢用戶和對應的用戶擴展信息,查詢結果映射為userAndInfoMap。

    代碼

    <?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.dao.UserMapper">
    
        <!--
        1. 配置user對象的映射,表的關聯映射每一列都要寫上,否則這一列是沒有值
        autoMapping 屬性:如果是同名的屬性,會自動映射
         -->
        <resultMap id="userMap" type="user">
            <!--主鍵映射-->
            <id property="id" column="id"/>
            <result property="username" column="username"/>
            <result property="birthday" column="birthday"/>
            <result property="sex" column="sex"/>
            <result property="address" column="address"/>
        </resultMap>
    
        <!--2. 配置userInfo對象的映射-->
        <resultMap id="userInfoMap" type="userInfo">
            <id property="id" column="id"/>
            <result property="height" column="height"/>
            <result property="weight" column="weight"/>
            <result property="married" column="married"/>
        </resultMap>
    
        <!--
        配置2者的1對1的關聯關系
        extends 這個映射是繼承于userMap的,相當于上面的所有映射關系繼承下來
        -->
        <resultMap id="userAndInfoMap" type="user" extends="userMap">
            <!--
            association配置1對1的關聯關系
            屬性:
                property 指定對方實體類的屬性名
                resultMap 指定對方的映射關系的id
            -->
            <association property="userInfo" resultMap="userInfoMap"/>
        </resultMap>
    
        <!--查詢結果就要指定上面的關聯的映射-->
        <select id="findUserAndInfo" resultMap="userAndInfoMap">
            select * from user u inner join user_info i on u.id = i.id where u.id = #{id}
        </select>
    </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.itheima.dao.UserMapper">
    
        <!--
        1. 配置user對象的映射,表的關聯映射每一列都要寫上,否則這一列是沒有值
        autoMapping 屬性:如果是同名的屬性,會自動映射
         -->
        <resultMap id="userMap" type="user" autoMapping="true"/>
    
        <!--2. 配置userInfo對象的映射-->
        <resultMap id="userInfoMap" type="userInfo" autoMapping="true"/>
    
        <!--
        配置2者的1對1的關聯關系
        extends 這個映射是繼承于userMap的,相當于上面的所有映射關系繼承下來
        -->
        <resultMap id="userAndInfoMap" type="user" extends="userMap" autoMapping="true">
            <!--
            association配置1對1的關聯關系
            屬性:
                property 指定對方實體類的屬性名
                resultMap 指定對方的映射關系的id
            -->
            <association property="userInfo" resultMap="userInfoMap"/>
        </resultMap>
    
        <!--查詢結果就要指定上面的關聯的映射-->
        <select id="findUserAndInfo" resultMap="userAndInfoMap">
            select * from user u inner join user_info i on u.id = i.id where u.id = #{id}
        </select>
    </mapper>
    

    測試

    查詢輸出用戶和擴展信息

    @Test
    public void testFindUserAndInfo() {
        //查詢用戶和他的信息表
        User user = userMapper.findUserAndInfo(1);
        System.out.println(user);
        //輸出他擴展信息
        System.out.println(user.getUserInfo());
    }
    

    執行效果

    在這里插入圖片描述

    小結

    association標簽的屬性 說明
    property 另一方實體類的屬性名字
    resultMap 另一方的映射id

    多表關聯:一對多關聯

    目標

    實現一對多的關聯映射

    分析用戶訂單數據模型

    在這里插入圖片描述

    表結構代碼

    -- 創建訂單表
    create table order_form(
        oid int primary key auto_increment ,   -- 主鍵
        user_id int not null,   -- 用戶id,外鍵
        number varchar(20),   -- 訂單編號
        create_time datetime,  -- 下單時間
        note varchar(100),   -- 備注
        foreign key(user_id) references user(id)   -- 外鍵約束,關聯主表的主鍵
    );
    
    -- 添加訂單數據
    insert into order_form values(null, 1,'10001001', now(), '請提前安裝'),(null, 1,'10001002', now(), '包郵'),(null, 1,'10001003', now(), '選擇紅色');
    insert into order_form values(null, 2,'10001004', now(), '購買多件'),(null, 2,'10001005', now(), '安全帶');
    
    select * from order_form;
    

    表與表的關系 在這里插入圖片描述

    需求

    查詢某個用戶,并且查詢關聯用戶的多個訂單信息,輸出這個用戶信息和他所有對應的所有訂單。

    編寫關聯查詢sql語句:查詢1號用戶的訂單

    select * from user u inner join order_form o on u.id = o.user_id where u.id = 1;
    

    查詢結果
    在這里插入圖片描述

    類之間的關系

    1. 在1方包含了一個多方的List集合
    2. 在多方中包含了一方的一個對象

    在這里插入圖片描述

    修改用戶訂單類OrderForm

    1. 添加一個用戶類
    2. 生成get和set方法
    package com.itheima.entity;
    
    import java.sql.Timestamp;
    
    /**
     * 訂單類(多方)
     */
    public class OrderForm {
    
        private Integer oid;
        private Integer userId;
        private String number;
        private Timestamp createTime;  //既有日期,又有時間
        private String note;
    
        private User user;  //包含1個1方對象
    
        @Override
        public String toString() {
            return "OrderForm{" +
                    "oid=" + oid +
                    ", userId=" + userId +
                    ", number='" + number + '\'' +
                    ", createTime=" + createTime +
                    ", note='" + note + '\'' +
                    '}';
        }
    
        public Integer getOid() {
            return oid;
        }
    
        public void setOid(Integer oid) {
            this.oid = oid;
        }
    
        public Integer getUserId() {
            return userId;
        }
    
        public void setUserId(Integer userId) {
            this.userId = userId;
        }
    
        public String getNumber() {
            return number;
        }
    
        public void setNumber(String number) {
            this.number = number;
        }
    
        public Timestamp getCreateTime() {
            return createTime;
        }
    
        public void setCreateTime(Timestamp createTime) {
            this.createTime = createTime;
        }
    
        public String getNote() {
            return note;
        }
    
        public void setNote(String note) {
            this.note = note;
        }
    
        public User getUser() {
            return user;
        }
    
        public void setUser(User user) {
            this.user = user;
        }
    }
    

    用戶實體類對象User

    1. 建立用戶到訂單的一對多關聯關系
    2. 在User中創建List<OrderForm> orders
    3. 生成get和set方法
    //體現了一對多的關系
    private List<OrderForm> orders;
    
    public List<OrderForm> getOrders() {
        return orders;
    }
    
    public void setOrders(List<OrderForm> orders) {
        this.orders = orders;
    }
    

    聲明UserMapper接口方法

    /**
     查詢某個用戶數據,并且關聯查詢用戶的所有訂單數據
     */
    User findUserAndOrders(int id);
    

    UserMapper.xml映射配置文件

    技術點

    collection的作用:映射1對多的關系

    步驟

    1. 定義訂單的映射orderMap
    2. 配置用戶到訂單的一對多關聯關系userOrdersMap,繼承于userMap
    3. collection:配置一對多關聯關系,指定property,ofType,resultMap為orderMap
    4. 查詢某個用戶,并且查詢關聯的多個訂單信息,結果為userOrdersMap

    sqlMapConfig.xml

    <settings>
        <!--映射下劃線為駝峰命名法,會自動將create_time對應createTime-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    

    UserMapper.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.dao.UserMapper">
    
        <!--
        1. 配置user對象的映射,表的關聯映射每一列都要寫上,否則這一列是沒有值
        autoMapping 屬性:如果是同名的屬性,會自動映射
         -->
        <resultMap id="userMap" type="user" autoMapping="true">
            <id property="id" column="id"/>
        </resultMap>
    
        <!--2. 配置userInfo對象的映射-->
        <resultMap id="userInfoMap" type="userInfo" autoMapping="true"/>
    
        <!--
        配置2者的1對1的關聯關系
        extends 這個映射是繼承于userMap的,相當于上面的所有映射關系繼承下來
        -->
        <resultMap id="userAndInfoMap" type="user" extends="userMap" autoMapping="true">
            <!--
            association配置1對1的關聯關系
            屬性:
                property 指定對方實體類的屬性名
                resultMap 指定對方的映射關系的id
            -->
            <association property="userInfo" resultMap="userInfoMap"/>
        </resultMap>
    
        <!--查詢結果就要指定上面的關聯的映射-->
        <select id="findUserAndInfo" resultMap="userAndInfoMap">
            select * from user u inner join user_info i on u.id = i.id where u.id = #{id}
        </select>
    
        <!--1. 用戶的映射在上面已經定義 -->
        <!--2. 定義訂單的映射,自動映射只會映射屬性和列名相同的 -->
        <resultMap id="orderMap" type="orderForm" autoMapping="true">
            <id column="oid" property="oid"/>
            <!--不同的列,需要手動映射-->
            <!--<result column="user_id" property="userId"/>
            <result column="create_time" property="createTime"/>-->
        </resultMap>
    
        <!--3.定義1對多的關聯映射-->
        <resultMap id="userAndOrderMap" type="user" extends="userMap" autoMapping="true">
            <!--
            collection 配置1對多的關聯關系
             屬性:property 定義多方的屬性名
                 resultMap 指定多方的映射關系的id
             -->
            <collection property="orders" resultMap="orderMap"/>
        </resultMap>
    
    
        <!--1對多的關聯查詢,查詢結果是上面1對多的關聯關系-->
        <select id="findUserAndOrders" resultMap="userAndOrderMap">
            select * from user u inner join order_form o on u.id = o.user_id where u.id = #{id}
        </select>
    </mapper>
    

    測試

    1. 查詢1號用戶的所有訂單
    2. 得到用戶信息
    3. 輸出這個用戶所有的訂單信息
    /**
     * 1對多
     */
    @Test
    public void testFindUserAndOrders() {
        User user = userMapper.findUserAndOrders(1);
        System.out.println(user);
        //得到他的訂單集合輸出
        List<OrderForm> orders = user.getOrders();
        System.out.println(orders);
    }
    

    執行效果

    在這里插入圖片描述

    小結

    collection的屬性 作用:映射1對多的關系
    property 指定多方的集合的屬性名
    resultMap 指定多方的映射id的值

    學習總結

    • resultMap標簽
    標簽 子標簽 說明
    <resultMap> 指定實體類與表列之間映射關系
    <id> 映射主鍵
    <result> 映射其它列
    屬性:autoMapping 用來自動映射相同的屬性和列,不同的還是要手動添加
    • 掌握MyBatis動態SQL

    if: 判斷如果條件為真,拼接標簽體中SQL語句

    where:

    1. 相當于where關鍵字
    2. 去掉多余的and, or, where關鍵字

    set:

    1. 用于update中,相當于set關鍵字
    2. 去掉多余的逗號

    foreach: 遍歷集合或數據,每個元素拼接一次

    foreach標簽中的屬性 說明
    collection 取值:list或array
    open 遍歷前添加的符號
    close 遍歷后添加的符號
    item 每次遍歷的變量名
    separator 每次遍歷添加的符號

    sql: 用來定義代碼塊

    include: 引用上面定義的代碼塊

    • 掌握MyBatis多表關聯查詢
    association標簽的屬性 1對1的關聯
    property 指定另一方的實體類的屬性名
    resultMap 指定另一方的映射id
    collection的屬性 1對多的關聯
    property 指定多方的實體類的屬性名
    resultMap 指定另一方的映射id

    AndOrders(1);
    System.out.println(user);
    //得到他的訂單集合輸出
    List orders = user.getOrders();
    System.out.println(orders);
    }

    
    ## 執行效果
    
    [外鏈圖片轉存中...(img-aiNHnEnr-1592726289154)]
    
    ## 小結
    
    | collection的屬性 | 作用:映射1對多的關系  |
    | :--------------- | ---------------------- |
    | property         | 指定多方的集合的屬性名 |
    | resultMap        | 指定多方的映射id的值   |
    
    
    
    # 學習總結
    
    - resultMap標簽
    
    | 標簽         | 子標簽            | 說明                                             |
    | ------------ | ----------------- | ------------------------------------------------ |
    | \<resultMap> |                   | 指定實體類與表列之間映射關系                     |
    |              | \<id>             | 映射主鍵                                         |
    |              | \<result>         | 映射其它列                                       |
    |              | 屬性:autoMapping | 用來自動映射相同的屬性和列,不同的還是要手動添加 |
    
    - 掌握MyBatis動態SQL
    
    if: 判斷如果條件為真,拼接標簽體中SQL語句
    
    where: 
    
    1. 相當于where關鍵字
    2. 去掉多余的and, or, where關鍵字
    
    set:
    
    1. 用于update中,相當于set關鍵字
    2. 去掉多余的逗號
    
    foreach: 遍歷集合或數據,每個元素拼接一次
    
    | foreach標簽中的屬性 | 說明               |
    | ------------------- | ------------------ |
    | collection          | 取值:list或array  |
    | open                | 遍歷前添加的符號   |
    | close               | 遍歷后添加的符號   |
    | item                | 每次遍歷的變量名   |
    | separator           | 每次遍歷添加的符號 |
    
    sql: 用來定義代碼塊
    
    include: 引用上面定義的代碼塊
    
     
    
    - 掌握MyBatis多表關聯查詢
    
    | association標簽的屬性 | 1對1的關聯                 |
    | --------------------- | -------------------------- |
    | property              | 指定另一方的實體類的屬性名 |
    | resultMap             | 指定另一方的映射id         |
    
    | collection的屬性 | 1對多的關聯              |
    | ---------------- | ------------------------ |
    | property         | 指定多方的實體類的屬性名 |
    | resultMap        | 指定另一方的映射id       |
    
    版權聲明:本文為du664754270原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/du664754270/article/details/106886646

    智能推薦

    用Python實現校園通知更新提醒

    前言 這個項目實已經在一個月前已經完成了,一直都想寫一篇博客來總結這個過程中遇到的一些問題。但最近一個月來都比較忙,所以一直拖到了現在。 首先說說起因吧,我沒事的時候,總喜歡依次點開學校主頁、教務處、圖書館以及學院的網站,看看有沒有什么新通知,雖然大多與我無關。恰逢最近正在學Python,經常聽到別人說用Python寫爬蟲很簡單,但自己尚未接觸過爬蟲。于是抱著試一試的心態看了幾篇關于Python爬...

    spring_ioc相關_第一章

    1 spring是一站式框架,在javaee的三層結構中,每一層都提供不提并的解決技術 web層:springMVC service層:spring的ioc dao層:spring的jdbcTemplate 2 javaee為避免兩個類之間出現耦合,則把對象的創建交給spring進行管理,spring的ioc操作:(1)ioc的配置文件方式;(2)ioc注解方式 3 ioc的底層原理使用技術(1)...

    【Python+OpenCV】視頻流局部區域像素值處理-一種特征提取方法

    參考我之前寫的處理圖片的文章:Python+OpenCV實現【圖片】局部區域像素值處理(改進版) 開發環境:Python3.6.0 + OpenCV3.2.0 任務目標:攝像頭采集圖像(例如:480*640),并對視頻流每一幀(灰度圖)特定矩形區域(480*30)像素值進行行求和,得到一個480*1的數組,用這480個數據繪制條形圖,即在逐幀采集視頻流并處理后“實時”顯示采...

    JavaWeb——【前端】——注冊頁面

    頁面效果 實現代碼 注意事項 主要使用的bootstrap樣式 如果想引用,不要直接復制,沒用的。 先介紹下所引用的文件: boostrap的js、bootstrap的css、jquery的js、以及自己編寫的register.css。 因為博主用的thymeleaf語法,所以有th符號。 若要使用時,根據個人情況導入相應的依賴。...

    網站HTTP升級HTTPS完全配置手冊

    本文由葡萄城技術團隊于博客園原創并首發 轉載請注明出處:葡萄城官網,葡萄城為開發者提供專業的開發工具、解決方案和服務,賦能開發者。 今天,所有使用Google Chrome穩定版的用戶迎來了v68正式版首個版本的發布,詳細版本號為v68.0.3440.75,上一個正式版v67.0.3396.99發布于6月13日,自Chrome 68起,當在加載非HTTPS站點時,都會在地址欄上明確標記為&ldqu...

    猜你喜歡

    echarts 自定義儀表盤設置背景圖片

    echarts儀表盤 使用插件 vue-echarts 代碼示例 HTML部分 js部分 效果圖...

    RT-Thread Studio部分定時器時鐘不正確的解決方案

    在昨天的RT-Thread Studio硬件定時器hwtimer在stm32f411上的使用筆記中,遇到了部分定時器速度想象中和實際不一致的情況,具體表現在定時器2、3、4、5、9、10、11都正常,但定時器1要快一倍。 仔細查看代碼,找到了原因。 因為代碼使用的是工程是直接生成的時鐘代碼,實際的時鐘頻率是這樣的: 而實際的定時器時鐘配置代碼如下: 針對F411,去掉其中的宏定義是這樣的: 這里說...

    symfony學習筆記之模板渲染-----twig總結

    參考:https://blog.csdn.net/liebert/article/details/77414217 目錄 一、模板引擎工作原理 二、Twig模板引擎 1.運行環境要求 2.基本API用法 3.設計模板 (1)變量輸出         a.全局變量         b.設置變量 (2)...

    小甲魚Python3學習筆記之第六講(僅記錄學習)

    第六講:python之常用操作符 一、知識點: 0.算術運算符:+,-,*,/,%(取模,即求余數),**(冪運算),//(地板除法,取整除,返回商的整數部分) 備注:①雙斜杠 // 除法總是向下取整。             ②從符點數到整數的轉換可能會舍入也可能截斷,建議使用math....

    Java 習題 (21)

    題目: 寫一個程序,打印從1 到 100 的值。 解答: 答案如下: (只是截取結果一部分) 如果覺得不錯,就用點贊或者關注來取代五星好評吧!...

    精品国产乱码久久久久久蜜桃不卡