第四章 MyBatis復(fù)雜映射和配置

1. MyBatis高級查詢

1.1 resultType和resultMap屬性

1.1.1 resultType

查詢結(jié)果返回的類型猾愿,返回的結(jié)果字段名一定是要相同的抡驼,不一致的話會映射不成功

<select id="findByLabelName" resultType="com.jin10.vo.LabelVo">
    select * from label where label_name = #{labelName}
</select>

1.1.2 resultMap

和上面的resultType相比歌殃,這個更加類似于自定義映射,可以解決復(fù)雜的映射問題外莲,也可以解決上面字段不一致導(dǎo)致的映射不成功的問題

<!--id當(dāng)前命名空間中的一個唯一標識,用于標識唯一一個resultMap,type表示類的完全限定名, 或者一個類型別名-->
<resultMap id="baseResultMap" type="com.jin10.vo.CategoriesVo">
    <!--主鍵id-->
    <id property="id" column="categories_id"></id>
    <!--數(shù)據(jù)庫中普通字段結(jié)果映射-->
    <result property="groupName" column="categories_name"></result>
    <result property="createTime"  column="create_time"></result>
</resultMap>

1.2 多條件查詢

三種方式進行多條件查詢:1. 傳遞pojo對象(推薦)裂垦;2. 使用注解@Param()獲取參數(shù)团赏;3. 使用序號進行代替

1.2.1 傳遞pojo對象

List<User> findByIdAndName(User user);
<select id="findByIdAndName" resultMap="baseResultMap" parameterType="com.lagou.domain.User">
    select * from user where id = #{user.id} and username = #{user.name};
</select>

1.2.2 使用注解進行獲取參數(shù)

List<User> findByIdAndName(@Param("id") Integer id, @Param("name") String name);
<select id="findByIdAndName" resultMap="baseResultMap">
    select * from user where id = #{id} and username = #{name};
</select>

1.2.3 使用序號傳遞參數(shù)

List<User> findByIdAndName(Integer id, String name);
<select id="findByIdAndName" resultMap="baseResultMap">
    select * from user where id = #{arg0} and username = #{arg1};
    <!--或者下面這種方式-->
    select * from user where id = #{param1} and username = #{param2};
</select>

總結(jié):相對比上面三種多條件查詢方式,傳遞pojo對象的方式會更加的直觀和方便,基于注解的方式也可以,第三種方式的話就適當(dāng)?shù)牧私庖幌拢惶扑]使用這種方式

1.3 模糊查詢

1.3.1 方式一终佛,使用#{}占位符進行查詢

List<User> findByUsername(String username);
<select id="findByUsername" resultMap="baseResultMap" parameterType="string">
    select * from user where like #{name};
</select>
public void test() {
    userMapper.findByUserName("%用戶名%");
}

1.3.2 方式二,使用${}進行查詢

List<User> findByUsername(String username);
<select id="findByUsername" resultMap="baseResultMap" parameterType="string">
    select * from user where like '${name}';
</select>
public void test() {
    userMapper.findByUserName("%用戶名%");
}

總結(jié):#{}和${}兩者之間的比較

  • {} 表示的是一個占位符雾家,在轉(zhuǎn)化為sql語句的時候會自動的添加上單引號

    • 實現(xiàn)preparedStatement向占位符中設(shè)置值铃彰,自動進行Java類型和JDBC類型轉(zhuǎn)換,可以有效地防止SQL注入
    • 可以接收簡單類型或者pojo屬性值
    • 如果parameterType傳遞單個簡單類型值芯咧,#{}括號中名稱可以隨便寫
  • ${} 表示拼接字符串

    • 將parameterType傳入的內(nèi)容拼接在sql中且不進行JDBC類型轉(zhuǎn)換牙捉,會出現(xiàn)sql注入的問題
    • 可以接收簡單類型或者pojo屬性值
    • 如果parameterType傳遞單個簡單類型值竹揍,#{}括號中名稱只能是value

2. 映射配置文件深入

2.1 返回主鍵

在應(yīng)用場景中,經(jīng)常會在插入數(shù)據(jù)之后進行返回當(dāng)前主鍵id邪铲,Mybatis提供了兩種返回插入數(shù)據(jù)的主鍵方式

2.1.1 方式一

public interface UserMapper() {
    int save(User user);
}
<!--
    useGeneratedKeys屬性:聲明返回主鍵
    keyProperty:把返回的主鍵值封裝到實體的id屬性中
-->
<insert id="save" parameterType="user" useGeneratedKeys="true" keyProperty="id"> 
    insert into 'user' (username, birthday, sex, address) values (#{user}, #{birthday}, #{sex}, #{address})
</insert>
public void test() {
    User insert = new User();
    insert.setUsername("測試名字");
    insert.setBirthday(new Date());
    insert.setSex("man");
    insert.setAddress("廣東廣州");
    userMapper.save(insert);
}

上面的這種方法不能滿足所有的數(shù)據(jù)庫芬位,對于數(shù)據(jù)庫本身沒有自動生成主鍵的Oracle來說是沒有作用的

2.1.2 方式二(適用于所有的數(shù)據(jù)庫)

public interface UserMapper() {
    int save(User user);
}
<!--
    keyColumn屬性:聲明返回主鍵
    keyProperty:把返回的主鍵值封裝到實體的id屬性中
    resultType: 指定主鍵的類型
    order: 設(shè)置在SQL語句執(zhí)行之前(后)執(zhí)行該語句,Oracle設(shè)置order為BEFORE
-->
<insert id="save" parameterType="user">
    <selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER"> 
        SELECT LAST_INSERT_ID();
    </selectKey> 
    insert into 'user' (username, birthday, sex, address) values (#{user}, #{birthday}, #{sex}, #{address})
</insert>
public void test() {
    User insert = new User();
    insert.setUsername("測試名字");
    insert.setBirthday(new Date());
    insert.setSex("man");
    insert.setAddress("廣東廣州");
    userMapper.save(insert);
}

2.2 動態(tài)SQL語句

動態(tài)SQL語句是MyBatis里面的一個重大特性

2.2.1 if標簽(很常用)

List<User> findByIf(User user);
<select id="findByIf" parameterType="user" resultType="User">
    select * from user
    <!-- Where標簽相當(dāng)于where 1=1带到,如果沒有條件昧碉,就不會拼接where關(guān)鍵字-->
    <where>
        <if test="id != null">
            AND id = #{id}
        </if>
        <if test="username != null">
            AND username = #{username}
        </if>
    </where>
</select>
public void test() {
    User select = new User();
    select.setId(10);
    select.setUsername("測試名字");
    userMapper.findByIf(select);
}

2.2.2 set標簽

更新操作使用set可以免去一些不必要的麻煩

void update();
<update id="update" parameterType="user">
    UPDATE user
    <!--
    set標簽的作用:
    1. 可以代替update 表名 set ...的SQL語句中的set關(guān)鍵字,使用set標簽會自動加上去
    2. 會自動去除最后一個條件的逗號
    -->
    <set>
        <if test="username != null">
            username = #{username},
        </if>
        <if test="birthday != null">
            birthday = #{birthday},
        </if>
        <if test="sex != null">
            sex = #{sex},
        </if>
        <if test="address != null">
            address = #{address},
        </if>
    </set>
    WHERE id = #{id}
</update>
public void test() {
    User select = new User();
    select.setId(10);
    select.setUsername("測試名字");
    insert.setBirthday(new Date());
    insert.setSex("man");
    insert.setAddress("廣東肇慶");
    userMapper.update(insert);
}

2.3 foreach標簽

常用場景是對集合進行遍歷

<foreach>標簽揽惹,它的屬性:

  • collection:代表要遍歷的集合元素
  • open:代表語句的開始部分
  • close:代表結(jié)束部分
  • item:代表遍歷集合的每個元素被饿,生成的變量名
  • sperator:代表分隔符

2.3.1 集合

List<User> findByList(List<Integer> ids);
<select id="findByList" resultType="User" parameterType="list">
    select * from `user`
    <where>
        <foreach collection="list" open="id in (" close=")" item="id" separator=",">
            #{id}
        </foreach>
    </where>
</select>
public void test() {
    List<Integer> ids = new ArrayList<>(); 
    ids.add(46); 
    ids.add(48); 
    ids.add(51);
    userMapper.findByList(ids);
}

2.3.2 數(shù)組

List<User> findByArray(List<Integer> ids);
<select id="findByArray" resultType="User" parameterType="int">
    select * from `user`
    <where>
        <foreach collection="array" open="id in (" close=")" item="id" separator=",">
            #{id}
        </foreach>
    </where>
</select>
public void test() {
    Integer[] ids = {46, 48, 51};
    userMapper.findByArray(ids);
}

如果是普通數(shù)組,collection屬性值為array

2.4 SQL片段

主要是將多個標簽出現(xiàn)重復(fù)的SQL語句進行抽取出來搪搏,然后在使用到的地方通過 include 引用狭握,從而達到重復(fù)使用的效果

<!--抽取的sql片段--> 
<sql id="selectUser"> 
    SELECT * FROM `user` 
</sql>

<select id="findByList" resultType="User" parameterType="list">
    <include refid="selectUser">
    <where>
        <foreach collection="list" open="id in (" close=")" item="id" separator=",">
            #{id}
        </foreach>
    </where>

</select>

3. 核心配置文件深入

3.1 plugins標簽

通過plugins標簽可以使用第三方的插件進行功能的擴展,例如pageHelper是將分頁的復(fù)雜操作進行封裝

使用步驟:

  • 導(dǎo)入PageHelper的相關(guān)依賴
<!-- 分頁助手 -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>3.7.5</version>
</dependency>
<dependency>
    <groupId>com.github.jsqlparser</groupId>
    <artifactId>jsqlparser</artifactId>
    <version>0.9.1</version>
</dependency>
  • 在MyBatis核心配置文件中配置PageHelper插件
<!-- 分頁助手的插件 -->
<plugin interceptor="com.github.pagehelper.PageHelper">
    <!-- 指定方言 -->
    <property name="dialect" value="mysql"/>
</plugin>
  • 測試
@Test 
public void testPageHelper() { 
    //設(shè)置分頁參數(shù) 
    PageHelper.startPage(1,2); 
    List<User> select = userMapper.select(null); 
    for(User user : select){ 
        System.out.println(user); 
        } 
    }

4. Mybatis多表查詢

數(shù)據(jù)準備

CREATE DATABASE `mybatis_db`;
USE `mybatis_db`;
CREATE TABLE `user` (  
`id` int(11) NOT NULL auto_increment,  
`username` varchar(32) NOT NULL COMMENT '用戶名稱',  
`birthday` datetime default NULL COMMENT '生日',  
`sex` char(1) default NULL COMMENT '性別',  
`address` varchar(256) default NULL COMMENT '地址',
 PRIMARY KEY  (`id`)) 
 ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- insert....
insert into `user`(`id`,`username`,`birthday`,`sex`,`address`) values (1,'子慕','2020-11-11 00:00:00','男','北京海淀'),(2,'應(yīng)顛','2020-12-12 00:00:00','男','北京海淀');

DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders` (  
`id` INT(11) NOT NULL AUTO_INCREMENT, 
`ordertime` VARCHAR(255) DEFAULT NULL,  
`total` DOUBLE DEFAULT NULL,  
`uid` INT(11) DEFAULT NULL,  
PRIMARY KEY (`id`),  
KEY `uid` (`uid`),  
CONSTRAINT `orders_ibfk_1` 
FOREIGN KEY (`uid`) 
REFERENCES `user` (`id`)) 
ENGINE=INNODB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-- ------------------------------ Records of orders-- ----------------------------
INSERT INTO `orders` VALUES ('1', '2020-12-12', '3000', '1');
INSERT INTO `orders` VALUES ('2', '2020-12-12', '4000', '1');
INSERT INTO `orders` VALUES ('3', '2020-12-12', '5000', '2');
-- ------------------------------ Table structure for sys_role-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (  
`id` INT(11) NOT NULL AUTO_INCREMENT, 
`rolename` VARCHAR(255) DEFAULT NULL,  
`roleDesc` VARCHAR(255) DEFAULT NULL,  
PRIMARY KEY (`id`)) 
ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
-- ------------------------------ Records of sys_role-- ----------------------------
INSERT INTO `sys_role` VALUES ('1', 'CTO', 'CTO');
INSERT INTO `sys_role` VALUES ('2', 'CEO', 'CEO');
------------------------------ Table structure for sys_user_role-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (  
`userid` INT(11) NOT NULL,  
`roleid` INT(11) NOT NULL,  
PRIMARY KEY (`userid`,`roleid`),  
KEY `roleid` (`roleid`),  
CONSTRAINT `sys_user_role_ibfk_1` 
FOREIGN KEY (`userid`) 
REFERENCES `sys_role`(`id`),  
CONSTRAINT `sys_user_role_ibfk_2` 
FOREIGN KEY (`roleid`) REFERENCES `user`(`id`)) 
ENGINE=INNODB DEFAULT CHARSET=utf8;
-- ------------------------------ Records of sys_user_role-- ----------------------------
INSERT INTO `sys_user_role` VALUES ('1', '1');
INSERT INTO `sys_user_role` VALUES ('2', '1');
INSERT INTO `sys_user_role` VALUES ('1', '2');
INSERT INTO `sys_user_role` VALUES ('2', '2');
SELECT * FROM orders o LEFT JOIN USER u ON o.`uid`=u.`id`;

4.1 一對一查詢

需求:查詢指定訂單號的訂單和對應(yīng)的用戶信息

SELECT * FROM orders o LEFT JOIN USER u ON o.`uid`=u.`id`;

4.1.1 代碼實現(xiàn)

Order實體類

package com.fuyi.entity;

import java.util.Date;

/**
 * @author raofy
 * @date 2021-05-11 17:34
 * @desc
 */
public class Order {

    private Integer id;

    private Date ordertime;

    private double money;

    @Override
    public String toString() {
        return "Order{" +
                "id=" + id +
                ", ordertime=" + ordertime +
                ", money=" + money +
                ", user=" + user +
                '}';
    }
}

編寫Mapper接口

package com.fuyi.mapper;

import com.fuyi.entity.Order;

import java.util.List;

/**
 * @author raofy
 * @date 2021-05-11 17:36
 * @desc
 */
public interface OrderMapper {

    /**
     * 查詢所有訂單和對應(yīng)的用戶信息(一對一疯溺,多對一)
     * @return
     */
    List<Order> findAllWithUser();
}

編寫Mapper.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.fuyi.mapper.OrderMapper">
    <resultMap id="baseResultMap" type="com.fuyi.entity.Order">
        <id property="id" column="id"></id>
        <result property="money" column="total"></result>
        <result property="ordertime" column="ordertime"></result>
        <!--
        一對多哥牍,多對一,使用association進行相關(guān)聯(lián)
        property="username" Java實體類的屬性名
        column="username"   表中字段名
        關(guān)聯(lián)條件id = uid
        -->
        <association property="user" javaType="com.fuyi.entity.User">
            <id property="id" column="uid"></id>
            <result property="username" column="username"></result>
            <result property="birthday" column="birthday"></result>
            <result property="sex" column="sex"></result>
            <result property="address" column="address"></result>
        </association>
    </resultMap>

    <select id="findAllWithUser" resultMap="baseResultMap">
        SELECT * FROM orders o left join user u on o.uid = u.id
    </select>
</mapper>

配置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>
    <!--環(huán)境配置-->
    <environments default="development">
        <!--使用MySQL環(huán)境-->
        <environment id="development">
            <!--使用JDBC類型事務(wù)管理器-->
            <transactionManager type="JDBC"></transactionManager>
            <!--使用連接池-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"></property>
                <property name="url" value="jdbc:mysql:///mybatis_db?useUnicode=true&characterEncoding=UTF-8"></property>
                <property name="username" value="root"></property>
                <property name="password" value="123456"></property>
            </dataSource>
        </environment>
    </environments>
    <!--加載映射配置-->
    <mappers>
        <!--批量加載-->
        <package name="com.fuyi.mapper"/>
    </mappers>
</configuration>

編寫測試類

package com.fuyi.test;

import com.fuyi.entity.Order;
import com.fuyi.mapper.OrderMapper;
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.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * @author raofy
 * @date 2021-05-11 17:49
 * @desc
 */
public class OrderTest {

    /**
     * 一對一喝检,多對一測試例子
     */
    @Test
    public void oneToOneTest() throws IOException {
        // 1. 加載核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");

        // 2. 獲取SQLFactory工廠對象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        // 3. 獲取SQLSession對象
        SqlSession sqlSession = factory.openSession();

        // 4. 獲取mapper
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);

        // 5. 執(zhí)行查詢
        List<Order> result = mapper.findAllWithUser();

        // 6. 打印結(jié)果
        result.forEach(System.out::println);

        sqlSession.close();

        resourceAsStream.close();
    }
}

總結(jié)

  • 編寫實體類
  • 編寫對應(yīng)的mapper接口
  • 編寫對應(yīng)的SQL語句和映射結(jié)果
  • 測試

4.2 一對多查詢

查詢所有用戶的對應(yīng)的用戶訂單表

4.2.1 編寫實體類

package com.fuyi.entity;

import java.util.Date;
import java.util.List;

/**
 * @author raofy
 */
public class User {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    private List<Order> orderList;
  
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                ", orderList=" + orderList +
                '}';
    }
}

4.2.2 編寫mapper

List<User> findAllWithOrder();

4.2.3 編寫mapper.xml文件

   <resultMap id="baseResultMap" type="com.fuyi.entity.User">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="birthday" column="birthday"></result>
        <result property="sex" column="sex"></result>
        <result property="address" column="address"></result>
        <!--
        一對多使用collection             標簽進行關(guān)聯(lián)
        property="orderList"           封裝到集合的屬性名
        ofType="com.fuyi.entity.Order" 封裝集合的泛型類型
        -->
        <collection property="orderList" ofType="com.fuyi.entity.Order">
            <id property="id" column="oid"></id>
            <result property="ordertime" column="ordertime"></result>
            <result property="money" column="total"></result>
        </collection>
    </resultMap>

    <select id="findAllWithOrder" resultMap="baseResultMap">
        select *, o.id oid from user u left join orders o on u.id = o.uid;
    </select>

4.2.4 測試

    @Test
    public void getUsersTest() throws IOException {
        // 1. 加載核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");

        // 2. 獲取SQLFactory工廠對象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        // 3. 獲取SQLSession對象
        SqlSession sqlSession = factory.openSession();

        // 4. 執(zhí)行SQL參數(shù)
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        // 5. 查詢
        List<User> result = mapper.findAllWithOrder();

        // 6. 打印
        result.forEach(System.out::println);

        // 7. 釋放資源
        sqlSession.close();
    }

4.3 多對多查詢

查詢所用用戶和對應(yīng)的角色身份

4.3.1 編寫實體類


package com.fuyi.entity;

/**
 * @author raofy
 * @version 1.0.0
 * @createTime 2021-05-13 23:21
 * @Description TODO
 */
public class SysRole {
    private Integer id;
    private String roleName;
    private String roleDesc;

    @Override
    public String toString() {
        return "SysRole{" +
                "id=" + id +
                ", roleName='" + roleName + '\'' +
                ", roleDesc='" + roleDesc + '\'' +
                '}';
    }
}

package com.fuyi.entity;

import java.util.Date;
import java.util.List;

/**
 * @author raofy
 */
public class User {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    private List<SysRole> roleList;
    private List<Order> orderList;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                ", roleList=" + roleList +
                ", orderList=" + orderList +
                '}';
    }
}

4.3.2 編寫mapper

List<User> findAllWithRole();

4.3.3 編寫mapper.xml

   <resultMap id="roleBaseResultMap" type="com.fuyi.entity.User">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="birthday" column="birthday"></result>
        <result property="sex" column="sex"></result>
        <result property="address" column="address"></result>
        <collection property="roleList" ofType="com.fuyi.entity.SysRole">
            <id property="id" column="rid"></id>
            <result property="roleName" column="roleName"></result>
            <result property="roleDesc" column="roleDesc"></result>
        </collection>
    </resultMap>

    <select id="findAllWithRole" resultMap="roleBaseResultMap">
        select u.*, sr.id rid, sr.rolename, sr.roleDesc
        from user u
        left join sys_user_role sur
        on u.id = sur.userid
        left join sys_role sr
        on sur.roleid = sr.id
    </select>

4.3.4 測試

   /**
     * 多對多關(guān)聯(lián)查詢
     *
     * @throws IOException
     */
    @Test
    public void manyToManyTest() throws IOException {
        // 1. 加載核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");

        // 2. 獲取SQLFactory工廠對象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        // 3. 獲取SQLSession對象
        SqlSession sqlSession = factory.openSession();

        // 4. 執(zhí)行SQL參數(shù)
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        // 5. 查詢
        List<User> result = mapper.findAllWithRole();

        // 6. 打印
        result.forEach(System.out::println);

        // 7. 釋放資源
        sqlSession.close();
    }

4.4 本章總結(jié)

在單表或者多表查詢種

  • 多對一(一對一)配置:使用resultMap和association標簽做映射配置
  • 一對多配置:使用resultMap和collection
  • 多對多配置:使用resultMap和collection
  • 多對多和一對多很相似,難度在于SQL語句的編寫

5. Mybatis嵌套查詢

什么是嵌套查詢撼泛,就是原本是多表查詢中的聯(lián)合語句拆分成各自的單表查詢挠说,再將他們嵌套起來進行查詢

5.1 一對一

需求查詢一個訂單并查詢出該訂單的用戶信息

5.1.1 SQL語句

# 查詢出指定id的訂單
select * from orders

# 通過上述查詢出的uid外鍵去查詢出用戶信息
select * from user where id = uid

5.1.2 編寫mapper

/**
  * 一對一嵌套查詢
  * @return
  */
List<Order> findAllAndUser();

5.1.3 Mapper.xml映射文件

  • OrderMapper.xml
    <resultMap id="nestedQueryResultMap" type="com.fuyi.entity.Order">
        <id property="id" column="id"></id>
        <result property="money" column="total"></result>
        <result property="ordertime" column="ordertime"></result>
        <association property="user" javaType="com.fuyi.entity.User" select="com.fuyi.mapper.UserMapper.findById" column="uid"></association>
    </resultMap>
    <select id="findAllAndUser" resultMap="nestedQueryResultMap">
        select * from orders
    </select>
  • UserMapper.xml
    <select id="findById" resultType="com.fuyi.entity.User" parameterType="integer">
        select * from user where id = #{id}
    </select>

5.1.4 測試類

   /**
     * 一對一,多對一嵌套查詢測試例子
     */
    @Test
    public void oneToOneNestedQueryTest() throws IOException {
        // 1. 加載核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");

        // 2. 獲取SQLFactory工廠對象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        // 3. 獲取SQLSession對象
        SqlSession sqlSession = factory.openSession();

        // 4. 獲取mapper
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);

        // 5. 執(zhí)行查詢
        List<Order> result = mapper.findAllAndUser();

        // 6. 打印結(jié)果
        result.forEach(System.out::println);

        sqlSession.close();

        resourceAsStream.close();
    }

5.1.5 總結(jié)

所謂的嵌套查詢愿题,就是使用association標簽進行調(diào)用其他的sql語句损俭,相比于多表查詢,將問題拆成多個小問題去解決潘酗,從而簡化了多表查詢操作

5.2 一對多

需求查詢所有用戶及訂單信息

5.2.1 SQL語句

# 查詢所有用戶
select * from user
# 通過用戶的id查詢所有訂單信息
select * from order where uid = id

5.2.2 編寫mapper

   /**
     * 一對多嵌套查詢
     *
     * @return
     */
    List<User> findAllAndOrder();

5.2.3 編寫mapper.xml映射文件

  • UserMapper.xml
    <resultMap id="nestedQueryResultMap" type="com.fuyi.entity.User">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="birthday" column="birthday"></result>
        <result property="sex" column="sex"></result>
        <result property="address" column="address"></result>
        <collection property="orderList" ofType="com.fuyi.entity.Order" column="id" select="com.fuyi.mapper.OrderMapper.findByUid"></collection>
    </resultMap>
    <select id="findAllAndOrder" resultMap="nestedQueryResultMap">
        select * from user
    </select>
  • OrderMapper.xml
    <select id="findByUid" resultType="com.fuyi.entity.Order">
        select * from orders where uid = #{id};
    </select>

5.2.4 測試

   /**
     * 一對多嵌套查詢
     *
     * @throws IOException
     */
    @Test
    public void oneToManyNestedQueryTest() throws IOException {
        // 1. 加載核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");

        // 2. 獲取SQLFactory工廠對象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        // 3. 獲取SQLSession對象
        SqlSession sqlSession = factory.openSession();

        // 4. 執(zhí)行SQL參數(shù)
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        // 5. 查詢
        List<User> result = mapper.findAllAndOrder();

        // 6. 打印
        result.forEach(System.out::println);

        // 7. 釋放資源
        sqlSession.close();
    }

5.3 多對多

需求:查詢用戶對應(yīng)的角色身份

5.3.1 SQL語句

# 查詢所有用戶
select * from user
# 根據(jù)用戶id查詢用戶的角色列表
select * from sys_role sr left join sys_user_role sur on sur.roleid = sr.id where sur.userid = id

5.3.2 編寫實體類

package com.fuyi.entity;

/**
 * @author raofy
 * @version 1.0.0
 * @createTime 2021-05-13 23:21
 */
public class SysRole {
    private Integer id;
    private String roleName;
    private String roleDesc;

    @Override
    public String toString() {
        return "SysRole{" +
                "id=" + id +
                ", roleName='" + roleName + '\'' +
                ", roleDesc='" + roleDesc + '\'' +
                '}';
    }
}

5.3.2 編寫mapper

public interface UserMapper {
    /**
     * 多對多嵌套查詢
     *
     * @return
     */
    List<User> findAllAndRole();
}

5.3.3 編寫mapper.xml映射文件

  • UserMapper.xml
    <resultMap id="nestedQueryRoleResultMap" type="com.fuyi.entity.User">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="birthday" column="birthday"></result>
        <result property="sex" column="sex"></result>
        <result property="address" column="address"></result>
        <collection property="roleList" ofType="com.fuyi.entity.SysRole" column="id" select="com.fuyi.mapper.SysRoleMapper.findByUid"></collection>
    </resultMap>
    <select id="findAllAndRole" resultMap="nestedQueryRoleResultMap">
        select * from user
    </select>
  • SysRoleMapper.xml
    <select id="findByUid" resultType="com.fuyi.entity.SysRole">
        select * from sys_role sr left join sys_user_role sur on sur.roleid = sr.id where sur.userid = #{id}
    </select>

5.3.4 測試

   /**
     * 多對多嵌套查詢
     *
     * @throws IOException
     */
    @Test
    public void manyToManyNestedQueryTest() throws IOException {
        // 1. 加載核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");

        // 2. 獲取SQLFactory工廠對象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        // 3. 獲取SQLSession對象
        SqlSession sqlSession = factory.openSession();

        // 4. 執(zhí)行SQL參數(shù)
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        // 5. 查詢
        List<User> result = mapper.findAllAndRole();

        // 6. 打印
        result.forEach(System.out::println);

        // 7. 釋放資源
        sqlSession.close();
    }

5.3.5 總結(jié)

  • 一對一配置:使用resultMap + association杆兵,通過column條件,執(zhí)行select查詢
  • 一對多配置:使用resultMap + collection仔夺,通過column條件琐脏,執(zhí)行select查詢
  • 多對多配置:使用resultMap + collection,通過column條件缸兔,執(zhí)行select查詢
  • 優(yōu)點:簡化多表查詢操作
  • 缺點:執(zhí)行多次sql語句日裙,浪費數(shù)據(jù)庫性
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市惰蜜,隨后出現(xiàn)的幾起案子昂拂,更是在濱河造成了極大的恐慌,老刑警劉巖抛猖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件格侯,死亡現(xiàn)場離奇詭異鼻听,居然都是意外死亡,警方通過查閱死者的電腦和手機联四,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門撑碴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人碎连,你說我怎么就攤上這事灰羽。” “怎么了鱼辙?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵廉嚼,是天一觀的道長。 經(jīng)常有香客問我倒戏,道長怠噪,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任杜跷,我火速辦了婚禮傍念,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘葛闷。我一直安慰自己憋槐,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布淑趾。 她就那樣靜靜地躺著阳仔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪扣泊。 梳的紋絲不亂的頭發(fā)上近范,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機與錄音延蟹,去河邊找鬼评矩。 笑死,一個胖子當(dāng)著我的面吹牛阱飘,可吹牛的內(nèi)容都是我干的斥杜。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼沥匈,長吁一口氣:“原來是場噩夢啊……” “哼果录!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起咐熙,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤弱恒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后棋恼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體返弹,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡锈玉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了义起。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拉背。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖默终,靈堂內(nèi)的尸體忽然破棺而出椅棺,到底是詐尸還是另有隱情,我是刑警寧澤齐蔽,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布两疚,位于F島的核電站,受9級特大地震影響含滴,放射性物質(zhì)發(fā)生泄漏诱渤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一谈况、第九天 我趴在偏房一處隱蔽的房頂上張望勺美。 院中可真熱鬧,春花似錦碑韵、人聲如沸赡茸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽占卧。三九已至,卻和暖如春治筒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背舷蒲。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工耸袜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人牲平。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓堤框,卻偏偏與公主長得像,于是被迫代替她去往敵國和親纵柿。 傳聞我的和親對象是個殘疾皇子蜈抓,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容