MyBatis 关于查询语句上配置的详细内容

mybatis · 浏览次数 : 9

小编点评

本文主要介绍了MyBatis在SQL查询结果返回不同类型的集合时的配置方法和相关概念。 **主要内容概述如下**: 1. **MyBatis 关于查询语句上配置的详细内容**: 本章介绍了MyBatis在SQL查询语句上配置的各种细节,包括别名、resultMap、驼峰命名规则等。 2. **准备工作**: 介绍了MyBatis的准备工作,包括数据表结构的设计和MyBatis的依赖配置。 3. **SQL查询结果,返回为POJO实体类型**: 讨论了如何将查询结果映射到POJO实体类,包括使用resultType属性指定实体类。 4. **SQL查询结果,返回为List集合类型**: 描述了当查询结果有多条记录时,如何使用List集合来接收这些记录。 5. **SQL查询结果,返回为Map集合**: 介绍了如何将查询结果映射到Map集合中,适用于没有合适的实体类POJO对应的情况。 6. **SQL查询结果,返回为List集合**: 讨论了当查询结果有多条记录时,如何使用List集合来接收这些记录。 7. **SQL查询结果,返回为Map**: 介绍了如何将查询结果映射到Map结构中,其中Map的key是Car的id。 8. **SQL查询结果,返回总记录条数**: 介绍了如何使用MyBatis获取查询结果的总记录条数。 9. **SQL查询,resultMap 结果映射**: 介绍了如何使用resultMap标签进行结果映射,以便在POJO实体类和数据库查询结果之间建立对应关系。 10. **总结**: 总结了本文的主要内容和关键点,强调了MyBatis配置和使用过程中的注意事项。 总的来说,本文详细介绍了MyBatis在SQL查询结果返回不同类型集合时的配置方法和相关概念,为开发者提供了全面的指导和参考。

正文

1. MyBatis 关于查询语句上配置的详细内容

@


2. 准备工作

数据表结构的设计,数据表名为:t_car

在这里插入图片描述

t_car 表中的数据信息:
在这里插入图片描述

pom.xml 文件当中配置相关的依赖的 jar 包如下:

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.rainbowsea</groupId>
    <artifactId>mybatis-005-crud-blog</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

    <dependencies>
        <!--        mybatis 的依赖-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.10</version>
        </dependency>

        <!--        mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

        <!--        引入 logback的依赖,这个日志框架实现了slf4j 规范-->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.11</version>
        </dependency>
    </dependencies>

</project>

配置 logback 的配置文件,用于打印显示,我们的日志信息,方便我们查看我们的运行过程,效果。

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>

<configuration debug="false">
    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>

    <!--mybatis log configure-->
    <logger name="com.apache.ibatis" level="TRACE"/>
    <logger name="java.sql.Connection" level="DEBUG"/>
    <logger name="java.sql.Statement" level="DEBUG"/>
    <logger name="java.sql.PreparedStatement" level="DEBUG"/>

    <!-- 日志输出级别,logback日志级别包括五个:TRACE < DEBUG < INFO < WARN < ERROR -->
    <root level="DEBUG">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="FILE"/>
    </root>

</configuration>

配置 MyBatis 的核心配置文件,

在这里插入图片描述

<?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>

        <!--  使用 <package>	还可以将这个包下的所有的类的全部自动起别名,别名就是简名,不区分大小写 -->
        <package name="com.rainbowsea.mybatis.pojo"/>
    </typeAliases>
    <environments default="mybatis">

        <environment id="mybatis">
            <!--            MANAGED 没有用第三框架管理的话,都是会被提交的,没有事务上的管理了 -->
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="MySQL123"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!-- 这里也是可以使用 package 包名扫描,但是同样的:对应接口路径要一致,接口名一致-->
        <package name="com.rainbowsea.mybatis.mapper"></package>
    </mappers>
</configuration>

对照 t_car 创建的ORM 映射的 Car 类

注意:在MyBatis 当中对应的ORM ,一般在框架里对应的 Bean实体类,一定要实现该 set 和 get 方法以及无参数构造方法,无法框架无法使用反射机制,进行操作

建议用包装类,这样可以防止 Null的问题,因为(简单类型 int num = null ,是不可以赋值为 null)的编译无法通过

在这里插入图片描述

package com.rainbowsea.mybatis.pojo;

public class Car {
    // 数据库表当中的字段应该和pojo类的属性一一对应
    // 建议使用包装类,这样可以防止null的问题
    private Long id;
    private String carNum;
    private String brand;
    private Double guidePrice;
    private String produceTime;
    private String carType;

    public Car() {
    }

    public Car(Long id, String carNum, String brand, Double guidePrice, String produceTime, String carType) {
        this.id = id;
        this.carNum = carNum;
        this.brand = brand;
        this.guidePrice = guidePrice;
        this.produceTime = produceTime;
        this.carType = carType;
    }

    @Override
    public String toString() {
        return "Car{" +
                "id=" + id +
                ", carNum='" + carNum + '\'' +
                ", brand='" + brand + '\'' +
                ", guidePrice=" + guidePrice +
                ", produceTime='" + produceTime + '\'' +
                ", catType='" + carType + '\'' +
                '}';
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getCarNum() {
        return carNum;
    }

    public void setCarNum(String carNum) {
        this.carNum = carNum;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public Double getGuidePrice() {
        return guidePrice;
    }

    public void setGuidePrice(Double guidePrice) {
        this.guidePrice = guidePrice;
    }

    public String getProduceTime() {
        return produceTime;
    }

    public void setProduceTime(String produceTime) {
        this.produceTime = produceTime;
    }

    public String getcarType() {
        return carType;
    }

    public void setcarType(String catType) {
        this.carType = catType;
    }
}

3. SQL查询结果,返回为POJO实体类型

当查询的结果,有对应的POJO 实体类,并且查询结果只有一条时:

实操:

对应的接口

在这里插入图片描述

package com.rianbowsea.mybatis.mapper;


import com.rianbowsea.mybatis.pojo.Car;

public interface CarMapper {
    /**
     * 根据 id 查询 Car 的值
     * @param id
     * @return
     */
    Car selectById(Long 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">

<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">

<!--    使用 as 别名,让POJO实体类当中的属性名与数据库的查询结果保持一致-->
    <select id="selectById" resultType="Car">
        SELECT id,
               car_num      as carNum,
               brand,
               guide_price  as guidePrice,
               produce_time as produceTime,
               car_type     as carType
        FROM `t_car`
        where id = #{id}
    </select>

</mapper>

运行测试:

查询id为 118 的记录结果:

在这里插入图片描述

package com.rainbowsea.mybatis.test;

import com.rainbowsea.mybatis.mapper.CarMapper;
import com.rainbowsea.mybatis.pojo.Car;
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;

public class CarMapperTest {


    @Test
    public void testSelectById() throws IOException {
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = mapper.selectById(118L);
        System.out.println(car);
    }
}

4. SQL查询结果,返回为List<POJO> 集合类型

当查询的记录条数是多条的时候,必须使用集合接收。如果使用单个实体类接收会出现异常。

在这里插入图片描述

import com.rainbowsea.mybatis.pojo.Car;

import java.util.List;

public interface CarMapper {

    /**
     * 获取所有的Car
     * @return
     */
    List<Car> selectAll();


}

注意:对于查询结果返回多条记录时,resultType的值是(集合/数组存储的元素的类型(除了Map集合是放Map集合本身))

在这里插入图片描述

<?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">

<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">

    <!--    使用 as 别名,让POJO实体类当中的属性名与数据库的查询结果保持一致-->
    <!--    注意:对于查询结果返回多条记录时,resultType的值是(集合/数组存储的元素的类型(除了Map集合是放Map集合本身))-->
    <select id="selectAll" resultType="Car">
        SELECT id,
               car_num      as carNum,
               brand,
               guide_price  as guidePrice,
               produce_time as produceTime,
               car_type     as carType
        FROM t_car
    </select>

</mapper>

运行测试:

查询t_car 数据表中所有的记录内容:

在这里插入图片描述

package com.rainbowsea.mybatis.test;

import com.rainbowsea.mybatis.mapper.CarMapper;
import com.rainbowsea.mybatis.pojo.Car;
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.util.List;

public class CarMapperTest {

    @Test
    public void testSelectAll() throws IOException {
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        List<Car> cars = mapper.selectAll();

        cars.forEach(car -> {
            System.out.println(car);
        });

        sqlSession.close();
    }

}

如果返回多条记录,采用单个实体类接收会怎样 ?

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

查询结果是一条的话可以使用List集合接收吗?当然可以

就是List 集合当中,只会存储一个记录的内容POJO

5. SQL查询结果,返回为Map 集合

当返回的数据,没有合适的实体类POJO对应的时候,可以采用Map集合进行接受,字段名做 : key ,字段值做:value ,查询结果可以保证只有一条数据,则返回一个Map集合。

注意:只有返回的是单个记录的时候,才可以用单个Map集合存储接受

Mybatis 在 查询结果放到 Map 集合中存放的方式是:

     * Map<String,     Object>
     *      key          value
     *     "id"        	 131
     *     "car_num"      999
     *     "brand"     	 小米su7
     *     查询数据库中的字段名          对于单个对应字段的值

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

import com.rainbowsea.mybatis.pojo.Car;

import java.util.List;
import java.util.Map;

public interface CarMapper {
    /**
     *  Mybatis 在 查询结果放到 Map 集合中存放的方式是:
     *  Map<String,     Object>
     *      k           v
     *     "id"         131
     *     "car_num"    999
     *     "brand"      小米su7
     *     查询          对于单个对应字段的值
     *     数据库中
     *     的字段名
     *
     *
     * @param id
     * @return
     */
    Map<String,Object> selectByIdRetMap(Long id);
}

注意:对于查询结果返回多条记录时,resultType的值是(集合/数组存储的元素的类型(除了Map集合是放Map集合本身))resultMap="map",这是因为mybatis内置了很多别名。【参见mybatis开发手册】 https://mybatis.net.cn/

在这里插入图片描述

<?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">

<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">

    <!--    使用 as 别名,让POJO实体类当中的属性名与数据库的查询结果保持一致-->
    <!--    注意:对于查询结果返回多条记录时,resultType的值是(集合/数组存储的元素的类型(除了Map集合是放Map集合本身))-->
    <select id="selectByIdRetMap" resultType="Map">
        SELECT id,
               car_num      as carNum,
               brand,
               guide_price  as guidePrice,
               produce_time as produceTime,
               car_type     as carType
        FROM t_car
        where id = #{id}
    </select>
</mapper>

运行测试:

查询 id 为 118 的记录

在这里插入图片描述

package com.rainbowsea.mybatis.test;

import com.rainbowsea.mybatis.mapper.CarMapper;
import com.rainbowsea.mybatis.pojo.Car;
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.util.List;
import java.util.Map;

public class CarMapperTest {

    @Test
    public void testSelectByIdRetMap() throws IOException {
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Map<String, Object> cars = mapper.selectByIdRetMap(118L);
        System.out.println(cars);

        sqlSession.close();
    }

}

在这里插入图片描述

注意:只有返回的是单个记录的时候,才可以用单个Map集合存储接受 ,如果是多个记录的话,

可以将Map集合放到List集合中。

反过来,如果返回的不是一条记录,是多条记录的话,只采用单个Map集合接收,这样同样会出现之前的异常:TooManyResultsException

在这里插入图片描述

6. SQL查询结果,返回为List<Map>集合

查询结果条数大于等于 1 条数据时,则可以返回一个存储 Map 集合的 List 集合。List<Map> 等同于 List<Car>

在这里插入图片描述

在这里插入图片描述

注意: 这个 resultType 不是 List 是 map ,注意:除了单个特殊的 Map 集合的话(因为Map当中存在多个元素类型,无法断定用其中的那个存储的),其他的都是数组/集合当中存放的数据的元素类型

在这里插入图片描述

<?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">

<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">

    <!--    使用 as 别名,让POJO实体类当中的属性名与数据库的查询结果保持一致-->
    <!--    这个 resultType 不是List 是 map ,注意:除了单个特殊的 Map -->
   <!--    这个 resultType 不是List 是 map ,注意:除了单个特殊的 Map 集合的话(因为Map当中存在多个元素类型,无法断定用其中的那个存储的),其他的都是数组/集合当中存放的数据的元素类型-->
    <select id="selectAllRetListMap" resultType="map">
        SELECT id,
               car_num      as carNum,
               brand,
               guide_price  as guidePrice,
               produce_time as produceTime,
               car_type     as carType
        FROM `t_car` 
    </select>

</mapper>

测试运行程序:

在这里插入图片描述

package com.rainbowsea.mybatis.test;

import com.rainbowsea.mybatis.mapper.CarMapper;
import com.rainbowsea.mybatis.pojo.Car;
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.util.List;
import java.util.Map;

public class CarMapperTest {


    @Test
    public void testSelectAllRetListMap() throws IOException {
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        List<Map<String, Object>> cars = mapper.selectAllRetListMap();
        cars.forEach(car->{
            System.out.println(car);
        });

        sqlSession.close();

    }

}

7. SQL查询结果,返回为Map<String,Map>

这里我们拿Car的id做 最外面的Map 的key,以后取出对应的Map集合时更方便。最外面里面包含一个小Map集合

在这里插入图片描述

这里我们需要使用 @MapKey 注解,该注解的作用就是将:将查询结果的 id 字段的值作为整个Map(最外面的那个Map)集合的key。

这里你想将查询结果中的那个字段的值,赋值给“最外面的Map”集合的 key ,就填写对应上的查询上的字段名即可

在这里插入图片描述

在这里插入图片描述

package com.rainbowsea.mybatis.mapper;


import com.rainbowsea.mybatis.pojo.Car;
import org.apache.ibatis.annotations.MapKey;

import java.util.List;
import java.util.Map;

public interface CarMapper {
    /**
     * 查询所有的Car,返回一个Map集合
     * Map集合的key是每条记录的主键值
     * Map集合的value是每条记录
     * @return
     */
    @MapKey("id") // 将查询结果的id字段的值作为整个Map集合的key。
    Map<Long,Map<String,Object>> selectAllRetMap();

}

注意:我们这里是一个Map中套装一个Map,

Map集合比较特殊(存在两个值:key,value) 所以要

继续使用Map存储查询结果

在这里插入图片描述

<?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">

<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">

    <!--    使用 as 别名,让POJO实体类当中的属性名与数据库的查询结果保持一致-->
<!--    注意:这里是用 Map集合进行接受的-->
    <select id="selectAllRetMap" resultType="Map">
        SELECT id,
               car_num      as carNum,
               brand,
               guide_price  as guidePrice,
               produce_time as produceTime,
               car_type     as carType
        FROM `t_car`
    </select>


</mapper>

运行测试:

查询t_car 数据表中的所有内容。

在这里插入图片描述

在这里插入图片描述

package com.rainbowsea.mybatis.test;

import com.rainbowsea.mybatis.mapper.CarMapper;
import com.rainbowsea.mybatis.pojo.Car;
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.util.List;
import java.util.Map;

public class CarMapperTest {

    @Test
    public void testSelectAllRetMap() throws IOException {
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Map<Long,Map<String,Object>> cars = mapper.selectAllRetMap();
        System.out.println(cars);
        sqlSession.close();
    }

}

8. SQL查询结果,返回总记录条数

在这里插入图片描述

import com.rainbowsea.mybatis.pojo.Car;
import org.apache.ibatis.annotations.MapKey;

import java.util.List;
import java.util.Map;

public interface CarMapper {

    /**
     * 获取Car的总记录条数
     * @return
     */
    Long selectTotal();
}

需要注意的是: select count(具体某个字段的话,是不会记录null值的个数的),所以我们可以用 select count(1) from t_car ,恒为真的方式,查询(这样就包括了为 null 的值的个数了)

在这里插入图片描述

<?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">

<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">
    <!--    <select id="selectTotal" resultType="java.lang.Long"> ,也可以用别名-->
    <select id="selectTotal" resultType="Long">
        select count(1)
        from t_car
    </select>

</mapper>

运行测试:

查询 t_car 数据表中的所有记录条数。

在这里插入图片描述

import java.io.IOException;
import java.util.List;
import java.util.Map;

public class CarMapperTest {

    @Test
    public void testSelectTotal() throws IOException {
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Long count = mapper.selectTotal();
        System.out.println("总记录条数" + count);
        sqlSession.close();

    }
}

9. SQL查询,resultMap 结果映射

我们知道,要将 select 查询的结果集存储到对应的POJO实体类当中的必须要将查询的字段名和POJO实体类的属性名两者保持一致 ,但是我们的数据库的命名规范是下划线 ,而在Java当中的命名规范是驼峰命名 方式,两者是不一致的。而想要将这两者在不修改自身的属性名字也能达到一个两者名字保持一致的方案有 ,如下三种方式:

  1. 第一种方式:使用 AS 关键字给列起别名
  2. 第二种方式:使用 resultMap 进行结果映射
  3. 第三种方式:开启MyBatis 的驼峰命名自动映射(配置 settings )

第一方式:我们上述的操作都是,使用的这种方式,下面就不多赘述了。

我们来学习一下,第二,三种方式。

9.1 第二种方式:使用 resultMap 进行结果映射

在这里插入图片描述



import com.rainbowsea.mybatis.pojo.Car;
import org.apache.ibatis.annotations.MapKey;

import java.util.List;
import java.util.Map;

public interface CarMapper {

    /**
     * 查询所有的Car信息,使用resultMap标签进行结果映射
     * @return
     */
    List<Car> selectAllByResultMap();
}

resultMap 1.专门定义一个结果映射,在这个结果映射当中指定数据库表的字段名和Java类的属性名的对应关系
type属性,用来指定POJO类的类名
id属性,指定resultMap的唯一标识,这个id将来要在select标签中使用,启用了别名机制, 也可以用别名

注意:resultMap属性的值必须和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">

<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">

    <!--  resultMap  1.专门定义一个结果映射,在这个结果映射当中指定数据库表的字段名和Java类的属性名的对应关系
            2.type属性,用来指定POJO类的类名
            3.id属性,指定resultMap的唯一标识,这个id将来要在select标签中使用-->
    <!--    <resultMap id="carResultMap" type="com.rainbowsea.mybatis.pojo.Car">-->
    <!--  启用了别名机制,  也可以用别名-->
    <resultMap id="carResultMap" type="Car">
        <!--        如果数据表中有主键,一般都是有主键的,要不然不符合数据库设计第一范式-->
        <!--        如果有主键,建议这里配置一个id的标签,注意:这不是必须的,但是官方的解释是:这样的配置可以让mybatis 提高效率-->
        <id property="id" column="id"></id>
        <!--        property 后面填写的值是:POJO类的属性名-->
        <!--        column 后面填写数据库表查询显示的的字段名(用了别名的话,是别名)-->
        <result property="carNum" column="car_num"></result>
        <!--当属性名和数据库列名一致时,可以省略。但建议都写上。-->
        <!--javaType用来指定属性类型。jdbcType用来指定列类型。一般可以省略。-->
        <result property="brand" column="brand" javaType="string" jdbcType="VARCHAR"/>
        <result property="guidePrice" column="guide_price"></result>
        <result property="produceTime" column="produce_time"></result>
        <result property="carType" column="car_type"></result>
    </resultMap>


    <!--    select标签的resultMap的属性,用来指定使用哪个结果映射,resultMap后面的值是resultMap的id-->
    <!--resultMap属性的值必须和resultMap标签中id属性值一致。-->
    <select id="selectAllByResultMap" resultMap="carResultMap">
        SELECT id,
               car_num,
               brand,
               guide_price,
               produce_time,
               car_type
        FROM `t_car`
    </select>

</mapper>

运行测试:

查询 t_car 数据表中的所有内容。

在这里插入图片描述


import com.rainbowsea.mybatis.mapper.CarMapper;
import com.rainbowsea.mybatis.pojo.Car;
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.util.List;
import java.util.Map;

public class CarMapperTest {

    @Test
    public void testSelectAllByResultMap() throws IOException {
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        List<Car> cars = mapper.selectAllByResultMap();
        cars.forEach(car -> {
            System.out.println(car);
        });

        sqlSession.close();
    }
}

9.2 第三种方式:开启驼峰命名自动映射

使用这种方式的前提是:属性名遵循Java驼峰 命名规范,数据库表列名遵循SQL的下划线 命名规范。

  • Java命名规范:首字母小写,后面每个单词首字母大写,遵循驼峰命名方式
  • SQL命名规范:全部小写,单词之间采用下划线分割

比如以下的对应关系:

比如以下的对应关系:

POJO 实体类中的属性名 数据库表的列名
carNum car_num
carType car_type
produceTime produce_time

如何启用该功能,在 mybatis-config.xml 文件中进行配置:

注意:setting 标签方式的位置,可以根据错误提示进行修正位置。

在这里插入图片描述

<!--    mybatis 的全局设置-->
    <settings>
<!--        是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 默认是 false 不开启,true 表示开启-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

<?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>

<!--    mybatis 的全局设置-->
    <settings>
<!--        是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 默认是 false 不开启,true 表示开启-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <!--    起别名-->
    <typeAliases>
        <!--  使用 <package>	还可以将这个包下的所有的类的全部自动起别名,别名就是简名,不区分大小写 -->
        <package name="com.rainbowsea.mybatis.pojo"/>
    </typeAliases>
    <environments default="mybatis">

        <environment id="mybatis">
            <!--            MANAGED 没有用第三框架管理的话,都是会被提交的,没有事务上的管理了 -->
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="MySQL123"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!-- 这里也是可以使用 package 包名扫描,但是同样的:对应接口路径要一致,接口名一致-->
        <package name="com.rainbowsea.mybatis.mapper"></package>
    </mappers>
</configuration>

开启后运行测试:

在这里插入图片描述

import com.rainbowsea.mybatis.pojo.Car;
import org.apache.ibatis.annotations.MapKey;

import java.util.List;
import java.util.Map;

public interface CarMapper {


    /**
     * mybatis 全局设置,驼峰命名映射
     * @return
     */
    List<Car> selectAllByMapUnderscoreToCamelCase();

}

在这里插入图片描述

<?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">

<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">
<!--    启用了 mybatis 全局设置,驼峰命名映射 -->
    <select id="selectAllByMapUnderscoreToCamelCase" resultType="Car">
        SELECT id,
               car_num,
               brand,
               guide_price,
               produce_time,
               car_type
        FROM `t_car`
    </select>

</mapper>

运行测试:

查询 t_car 数据表的所有记录

在这里插入图片描述


import com.rainbowsea.mybatis.mapper.CarMapper;
import com.rainbowsea.mybatis.pojo.Car;
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.util.List;
import java.util.Map;

public class CarMapperTest {

    @Test
    public void testSelectAllByMapUnderscoreToCamelCase() throws IOException {
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        List<Car> cars = mapper.selectAllByMapUnderscoreToCamelCase();
        cars.forEach(car -> {
            System.out.println(car);
        });

        sqlSession.close();
    }
}

10. 总结:

  1. 注意:对于查询结果返回多条记录时,resultType的值是(集合/数组存储的元素的类型(除了Map集合是放Map集合本身))

  2. 注意:只有返回的是单个记录的时候,才可以用单个Map集合存储接受 ,如果是多个记录的话,可以将Map集合放到List集合中。反过来,如果返回的不是一条记录,是多条记录的话,只采用单个Map集合接收,这样同样会出现之前的异常:TooManyResultsException

  3. 这里我们需要使用 @MapKey 注解,该注解的作用就是将:将查询结果的 id 字段的值作为整个Map(最外面的那个Map)集合的key。

     这里你想将查询结果中的那个字段的值,赋值给“最外面的Map”集合的 key ,就填写对应上的查询上的字段名即可
    
  4. resultMap 结果映射: 注意:resultMap属性的值必须和resultMap标签中id属性值一致。property 后面填写的值是:POJO类的属性名;column 后面填写数据库表查询显示的的字段名(用了别名的话,是别名)

  5. 开启驼峰命名自动映射。属性名遵循Java驼峰 命名规范,数据库表列名遵循SQL的下划线 命名规范。,同时注意:注意:setting 标签方式的位置,可以根据错误提示进行修正位置。

  6. 如果查询的结果是一个数值,则可以用数值类型进行接受。

11. 最后:

“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”

在这里插入图片描述

与MyBatis 关于查询语句上配置的详细内容相似的内容:

MyBatis 关于查询语句上配置的详细内容

1. MyBatis 关于查询语句上配置的详细内容 @目录1. MyBatis 关于查询语句上配置的详细内容2. 准备工作3. SQL查询结果,返回为POJO实体类型4. SQL查询结果,返回为List 集合类型5. SQL查询结果,返回为Map 集合6. SQL查询结果,返回为List

面试必会 --> MyBatis篇

什么是MyBatis Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。程序员直接编写原生态sql,可以严格控制sql执行性能,灵活度高。 MyBatis 可以使用 XM

【简写Mybatis-02】注册机的实现以及SqlSession处理

学习源码一定一定不要太关注代码的编写,而是注意代码实现思想:通过设问方式来体现代码中的思想;方法:5W+1H

Mybatis执行器

mybatis执行sql语句的操作是由执行器(Executor)完成的,mybatis中一共提供了3种Executor: 类型 名称 功能 REUSE 重用执行器 缓存PreparedStatement,下一次执行相同的sql可重用 BATCH 批量执行器 将修改操作记录在本地,等待程序触发或有下一

『手写Mybatis』实现映射器的注册和使用

前言 如何面对复杂系统的设计? 我们可以把 Spring、MyBatis、Dubbo 这样的大型框架或者一些公司内部的较核心的项目,都可以称为复杂的系统。 这样的工程也不在是初学编程手里的玩具项目,没有所谓的 CRUD,更多时候要面对的都是对系统分层的结构设计和聚合逻辑功能的实现,再通过层层转换进行

MyBatis 的缓存机制

1. MyBatis 的缓存机制 @目录1. MyBatis 的缓存机制2. 准备工作3. MyBatis 的一级缓存3.1 一级缓存失效情况/条件4. MyBatis 的二级缓存5. MyBatis 集成 EhCache 第三方缓存6. 总结:7. 最后: 缓存(Cache) 缓存的作用:通过减少

MyBatis的逆向工程详细步骤操作

1. MyBatis的逆向工程详细步骤操作 @目录1. MyBatis的逆向工程详细步骤操作2. 逆向工程配置与生成2.1 MyBatis3Simple:基础版,只有基本的增删改查2.1.1 第一步:在pom.xml 中添加逆向工程插件2.1.2 第二步:配置 generatorConfig.xml

MyBatis 的在使用上的注意事项及其辨析

1. MyBatis 的在使用上的注意事项及其辨析 @目录1. MyBatis 的在使用上的注意事项及其辨析2. 准备工作3. #{ } 与 ${ } 的区别和使用{}3.1 什么情况下必须使用 $3.1.1 拼接表名3.1.2 批量删除3.1.3 模糊查询3.1.3.1 使用 ${ }的方式3.1

从Mybatis-Plus开始认识SerializedLambda

从Mybatis-Plus开始认识SerializedLambda 背景 对于使用过Mybatis-Plus的Java开发者来说,肯定对以下代码不陌生: @TableName("t_user") @Data public class User { private String id; private

Mybatis-Plus最优化持久层开发

Mybatis-plus:最优化持久层开发 一:Mybatis-plus快速入门: 1.1:简介: Mybatis-plus(简称MP)是一个Mybatis的增强工具,在mybatis的基础上只做增强不做改变; 提高效率; 自动生成单表的CRUD功能; 提供了丰富的条件拼接方式; 全自动ORM类型持