Mybatis之resultMap详解

resultMap作用是处理数据表中字段与java实体类中属性的映射关系。

准备工作

① 创建数据库&数据表

CREATE DATABASE `dbtest1`;

CREATE TABLE `t_emp` (
  `emp_id` int NOT NULL AUTO_INCREMENT,
  `emp_name` varchar(20) DEFAULT NULL,
  `age` int DEFAULT NULL,
  `gender` char(1) DEFAULT NULL,
  `dept_id` int DEFAULT NULL,
  PRIMARY KEY (`emp_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

CREATE TABLE `t_dept` (
  `dept_id` int DEFAULT NULL,
  `dept_name` varchar(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

② 创建实体类Emp.java&Dept.java

public class Dept {

    private int deptId;

    private String deptName;

    //一对多关系(一个部门对应多个员工)
    private List<Emp> emps;

    public Dept() {
    }

    public Dept(int deptId, String deptName, List<Emp> emps) {
        this.deptId = deptId;
        this.deptName = deptName;
        this.emps = emps;
    }

    public int getDeptId() {
        return deptId;
    }

    public void setDeptId(int deptId) {
        this.deptId = deptId;
    }

    public String getDeptName() {
        return deptName;
    }

    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }

    public List<Emp> getEmps() {
        return emps;
    }

    public void setEmps(List<Emp> emps) {
        this.emps = emps;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "deptId=" + deptId +
                ", deptName='" + deptName + '\'' +
                ", emps=" + emps +
                '}';
    }
}
public class Emp {

    private int empId;
    private String empName;

    private int age;
    private String gender;

    //多对一关系(多个员工对应一个部门)
    private Dept dept;

    public Emp() {
    }

    public Emp(int empId, String empName, int age, String gender, Dept dept) {
        this.empId = empId;
        this.empName = empName;
        this.age = age;
        this.gender = gender;
        this.dept = dept;
    }

    public int getEmpId() {
        return empId;
    }

    public void setEmpId(int empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "empId=" + empId +
                ", empName='" + empName + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", dept=" + dept +
                '}';
    }
}

③ 创建jdbc.properties,添加如下内容

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/dbtest1?serverTimezone=UTC
jdbc.username=root
jdbc.password=123456

jdbc.driverClassName=com.mysql.jdbc.Driver

④ 创建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>
    
    <!-- 引入properties文件 -->
    <properties resource="jdbc.properties"/>
    
    <!-- 设置全局配置 -->
    <settings>
        <!-- 开启将数据表中字段名下划线命名为驼峰命名规则 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!-- 开启延迟加载 -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 按需加载 -->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
    
    <!-- 设置类型别名 -->
    <typeAliases>
        <!-- 以包为单位,Java实体类别名为类名且不区分大小写 -->
        <package name="com.evan.mybatis.entity"/>
    </typeAliases>

    <!-- 配置连接数据库环境 -->
    <environments default="mysql8">
        <!-- 连接mysql8数据库环境 -->
        <environment id="mysql8">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>

        <!-- 连接mysql5数据库环境 -->
        <environment id="mysql5">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driverClassName}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 引入mybatis映射文件 -->
    <mappers>
        <package name="com.evan.mybatis.mapper"/>
    </mappers>
</configuration>

⑤ 添加依赖

    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
        </dependency>
    </dependencies>

⑥ 创建SqlSession工具类

public class SqlSessionUtil {

    private static final Log logger = LogFactory.getLog(SqlSessionUtil.class);

    public static SqlSession getSqlSession() {
        SqlSession sqlSession = null;
        try(InputStream is = Resources.getResourceAsStream("mybatis-config.xml");) {
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
            sqlSession = sqlSessionFactory.openSession(true);
        } catch (IOException e) {
            logger.error(e);
        }
        return sqlSession;

    }
}

字段和属性的映射关系处理方案

数据表中字段名与属性名不一致的情况

    /**
     * 根据id查询员工信息
     * @param empId
     * @return
     */
    Emp getEmpById(@Param("id") Integer empId);
  • 方式一:给字段起别名,别名与属性名一致
<select id="getEmpById" resultType="com.evan.mybatis.entity.Emp">
    select emp_id empId,emp_name empName,age,gender from t_emp where emp_id = #{empId}
</select>
  • 方式二:设置全局配置,将字段名下换线自动映射为属性名驼峰规则
<settings>
    <!-- 将数据表中字段下划线(_)映射为驼峰命名 -->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<select id="getEmpById" resultType="com.evan.mybatis.entity.Emp">
    select emp_id ,emp_name,age,gender from t_emp where emp_id = #{empId}
</select>
  • 方式三:使用ResultMap自定义映射处理
<!--
resultMap标签:设置自定义映射关系
属性:
id:标识自定义映射关系的唯一标识符
type:表示查询数据要映射的实体类类型
-->
<resultMap id="empResultMap" type="emp">
	<!--
	id标签:处理主键与实体类中id的映射关系
	result标签:处理数据表中字段与实体类中属性的映射关系
	属性:
	column:处理映射关系中数据表中的字段名
	property:处理映射关系中实体类中的属性名
	jdbcType:数据表中的字段类型
	javaType:实体类中的属性类型
	-->
	<!--
	<id column="emp_id" property="empId" jdbcType="INTEGER"/>
	<result column="emp_name" property="empName" jdbcType="VARCHAR"/>
	<result column="age" property="age" jdbcType="INTEGER"/>
	<result column="gender" property="gender" jdbcType="CHAR"/>
	-->
	<id column="emp_id" property="empId" javaType="java.lang.Integer"/>
	<result column="emp_name" property="empName" javaType="java.lang.String"/>
	<result column="age" property="age" javaType="java.lang.Integer"/>
	<result column="gender" property="gender" javaType="java.lang.String"/>
</resultMap>
<select id="getEmpById" resultMap="empResultMap">
	select emp_id,emp_name,age,gender
	from t_emp
	where emp_id = #{id}
</select>

结论:
若字段名和实体类中的属性名不一致,但是字段名符合数据库的规则(使用),实体类中的属性名符合Java的规则(使用驼峰)。
此时也可通过以下两种方式处理字段名和实体类中的属性的映射关系。

  • 可以通过为字段起别名的方式,保证和实体类中的属性名保持一致。
  • 可以在MyBatis的核心配置文件中设置一个全局配置信息mapUnderscoreToCamelCase,可以在查询表中数据时,自动将下划线类型的字段名转换为驼峰。
    例如:字段名user_name,设置了mapUnderscoreToCamelCase,此时字段名就会转换为 userName
测试
    @Test
    public void test1() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        System.out.println(mapper.getEmpById(5));
        sqlSession.close();
    }

多对一的关系映射处理

查询员工信息以及员工所对应的部门信息。

  • 方式一: 级联属性赋值处理
/**
* 获取员工及所对应的部门信息
* @param empId
* @return
*/
Emp getEmpAndDeptById(@Param("empId") Integer empId);
<!-- 多对一映射关系:级联属性赋值 -->
<resultMap id="empAndDeptResultMap" type="emp">
	<id column="emp_id" property="empId" javaType="java.lang.Integer"/>
	<result column="emp_name" property="empName" javaType="java.lang.String"/>
	<result column="age" property="age" javaType="java.lang.Integer"/>
	<result column="gender" property="gender" javaType="java.lang.String"/>
	<result column="dept_id" property="dept.deptId" javaType="java.lang.Integer"/>
	<result column="dept_name" property="dept.deptName" javaType="java.lang.String"/>
</resultMap>
<select id="getEmpAdnDeptById" resultMap="empAndDeptResultMap">
	SELECT
		t_emp.*,t_dept.`dept_name`
	FROM
		t_emp LEFT JOIN t_dept ON t_emp.`dept_id`=t_dept.`dept_id`
	WHERE
		t_emp.emp_id = #{id}
</select>
  • 方式二:使用<association>标签
<!-- 多对一映射关系:association标签 -->
<resultMap id="empAndDeptResultMap" type="emp">
	<id column="emp_id" property="empId" javaType="java.lang.Integer"/>
	<result column="emp_name" property="empName" javaType="java.lang.String"/>
	<result column="age" property="age" javaType="java.lang.Integer"/>
	<result column="gender" property="gender" javaType="java.lang.String"/>
	<!--
	association:处理多对一的映射关系(处理实体类类型的属性)
	property:设置需要处理映射关系的属性的属性名
	javaType:设置需要处理的属性的类型
	-->
	<association property="dept" javaType="dept">
		<id column="dept_id" property="deptId"/>
		<result column="dept_name" property="deptName"/>
	</association>
</resultMap>
<select id="getEmpAdnDeptById" resultMap="empAndDeptResultMap">
	SELECT
		t_emp.*,t_dept.`dept_name`
	FROM
		t_emp LEFT JOIN t_dept ON t_emp.`dept_id`=t_dept.`dept_id`
	WHERE
		t_emp.emp_id = #{id}
</select>
测试
    @Test
    public void test2() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        System.out.println(mapper.getEmpAdnDeptById(2));
        sqlSession.close();
    }
  • 方式三:使用<association>标签进行分步查询

Step 1:查询员工信息

public interface EmpMapper {

    /**
     * 第一步:通过分步查询员工及所对应的部门信息
     * @param empId
     * @return
     */
    Emp getEmpAndDeptByStepOne(@Param("empId") Integer empId);
}

Step 2:查询部门信息

public interface DeptMapper {

    /**
     * 第二步:通过分步查询员工及所对应的部门信息
     * @param deptId
     * @return
     */
    Dept getEmpAndDeptByStepTwo(@Param("deptId") Integer deptId);
}
<!-- 部门信息查询 -->
<select id="getEmpAndDeptByStepTwo" resultType="com.evan.mybatis.entity.Dept">
     select * from t_dept where dept_id = #{deptId}
</select>
<!-- 多对一映射关系: 分步查询 -->
<resultMap id="empAndDeptByStepResultMap" type="emp">
	<id column="emp_id" property="empId"/>
	<result column="emp_name" property="empName"/>
	<result column="age" property="age"/>
	<result column="gender" property="gender"/>
	<!--
		select设置分步查询的sql唯一标识(namespace.SQLId或mapper接口的全类名.方法名)
		column:将查询出的某个字段作为分步查询的sql条件
		fetchType:当开启了全局延迟加载之后,通过该属性设置当前分步查询是否使用延迟加载
			lazy:表示延迟加载
			eager:表示立即加载
	-->
	<association property="dept" javaType="dept" fetchType="lazy"
				 select="com.evan.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
				 column="dept_id"/>
</resultMap>
<select id="getEmpAndDeptByStepOne" resultMap="empAndDeptByStepResultMap">
	SELECT * FROM t_emp WHERE emp_id = #{empId}
</select>

在Mybatis核心配置文件中设置全局延迟加载:

<settings>
    <!-- 开启延迟加载 -->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!--
        按需加载:
        当开启延迟加载时同时设置该属性是否按需加载,默认true按需加载
        若为false:加载全部字段信息,不管你是否需要这个字段信息
        若为true:按需加载,按照需要的字段查询加载
        -->
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

结论:
分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息:
lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。
aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载。
此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可通过associationcollection中fetchType属性设置当前的分步查询是否使用延迟加载,fetchType="lazy(延迟加载)|eager(立即加载)"

测试
    @Test
    public void test3() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        System.out.println(mapper.getEmpAndDeptByStepOne(5));
        sqlSession.close();
    }

一对多的关系映射处理

  • 方式一:使用<conllection>标签
    /**
     * 根据部门id查询部门以及部门中所对应的员工信息
     * @param deptId
     * @return
     */
    Dept getDeptAndEmpById(@Param("deptId") Integer deptId);
<!-- 一对多映射关系: 使用<collection>标签 -->
<resultMap id="deptAndEmpResultMap" type="dept">
	<id column="dept_id" property="deptId" javaType="java.lang.Integer"/>
	<result column="dept_name" property="deptName" javaType="java.lang.String"/>
	<!--
	   collection: 处理一对多的映射关系
	   ofType:设置集合类型属性中存储的数据类型
	-->
	<collection property="emps" ofType="emp">
		<id column="emp_id" property="empId" javaType="java.lang.Integer"/>
		<result column="emp_name" property="empName" javaType="java.lang.String"/>
		<result column="age" property="age" javaType="java.lang.Integer"/>
		<result column="gender" property="gender" javaType="java.lang.String"/>
	</collection>
</resultMap>
<select id="getDeptAndEmpById" resultMap="deptAndEmpResultMap">
	SELECT
		t_emp.*,t_dept.`dept_name`
	FROM t_dept
			 LEFT JOIN t_emp ON t_dept.`dept_id` = t_emp.`dept_id`
	WHERE t_dept.`dept_id` = #{deptId}
</select>
  • 方式二:分步查询
    /**
     * 分步查询第一步:根据id查询部门信息
     * @param deptId
     * @return
     */
    Dept getDeptById(@Param("deptId") Integer deptId);
    /**
     * 分步查询第二步: 根据部门id查询部门所属员工
     * @param deptId
     * @return
     */
    List<Emp> getEmpListByDeptId(Integer deptId);
    <select id="getEmpListByDeptId" resultType="com.evan.mybatis.entity.Emp">
        select * from t_emp where dept_id = #{deptId}
    </select>
<!-- 一对多映射关系: 分步查询 -->
<!--
  分步查询步骤:
      先根据id查询一对多关系主表的信息,然后将查询出的主表id作为查询条件,去找<select>标签中的查询信息,并将两个分步查询处理的信息按照<property>标签的属性类型接收
      说明:
      property="emps":emps是实体类中的属性名,由于emps属性类型是list集合,所以<select>中的
      查询方法返回类型也是使用List集合
	  select、property、column三者之间的关系:
	  根据select的column查询出来的结果,封装到property,显示最终结果集
-->
<resultMap id="deptAndEmpByStepResultMap" type="dept">
	<id column="dept_id" property="deptId" javaType="java.lang.Integer"/>
	<result column="dept_name" property="deptName" javaType="java.lang.String"/>
	<collection property="emps" column="dept_id"
		select="com.evan.mybatis.mapper.EmpMapper.getEmpListByDeptId"/>
</resultMap>
<select id="getDeptById" resultMap="deptAndEmpByStepResultMap">
	select * from t_dept where dept_id = #{deptId}
</select>
测试
  • 分步查询测试
@Test
public void test5() {
	SqlSession sqlSession = SqlSessionUtil.getSqlSession();
	DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
	Dept dept = mapper.getDeptById(2);
	System.out.println(dept);
	sqlSession.close();
}

测试结果:

image

结果可以看到,多条查询语句执行。

  • 按需查询
@Test
public void test5() {
	SqlSession sqlSession = SqlSessionUtil.getSqlSession();
	DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
	Dept dept = mapper.getDeptById(2);
	System.out.println(dept.getDeptName());
	sqlSession.close();
}

测试结果:

image

开启延迟加载以后,可以看到按照需求查询指定SQL执行。

原文地址:https://www.cnblogs.com/lisong0626/p/18004272

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


1.pom.xml引入依赖 &lt;dependency&gt; &lt;groupId&gt;com.github.pagehelper&lt;/groupId&gt; &lt;artifactId&gt;pagehelper&lt;/artifactId&gt; &lt;version&gt;5
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt; &lt;!DOCTYPE configuration PUBLIC &quot;-//mybatis.org//DTD Config 3.0//EN&quot; &qu
准备工作 ① 创建数据库&amp;数据表 ## 创建数据库 CREATE DATABASE `dbtest1`; ## 创建数据表 CREATE TABLE `t_user` ( `id` INT NOT NULL AUTO_INCREMENT, `username` VARCHAR(20) DEF
MyBatis逆向工程是指根据数据库表结构自动生成对应的实体类、Mapper接口以及SQL映射文件的过程。这个过程可以通过MyBatis提供的逆向工程工具来完成,极大地方便了开发人员,避免了重复的代码编写,提高了开发效率。 创建逆向工程的步骤 1、添加依赖&amp;插件 &lt;!-- 控制Mave
MyBatis获取参数值的两种方式:${}和#{} ${}的本质就是字符串拼接,#{}的本质就是占位符赋值。 ${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;但是#{}使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自
resultMap作用是处理数据表中字段与java实体类中属性的映射关系。 准备工作 ① 创建数据库&amp;数据表 CREATE DATABASE `dbtest1`; CREATE TABLE `t_emp` ( `emp_id` int NOT NULL AUTO_INCREMENT, `em
EHCache缓存针对于MyBatis的二级缓存。 MyBatis默认二级缓存是SqlSessionFactory级别的。 添加依赖 &lt;!-- MyBatis-EHCache整合包 --&gt; &lt;dependency&gt; &lt;groupId&gt;org.mybatis.cac
MyBatis 提供了一级缓存和二级缓存的支持,用于提高数据库查询的性能,减少不必要的数据库访问。 一级缓存(SqlSession 级别的缓存) 一级缓存是 MyBatis 中最细粒度的缓存,也称为本地缓存。它存在于每个 SqlSession 的生命周期中,当 SqlSession 被关闭或清空时,
动态SQL是 MyBatis 中非常强大且灵活的功能,允许你根据不同的条件构建SQL查询。 这主要通过 &lt;if&gt;、&lt;choose&gt;、&lt;when&gt;、&lt;otherwise&gt;、&lt;foreach&gt;等标签实现。 查询场景 /** * 根据条件查询员工
本教程操作系统:windows10系统、DELL G3电脑。 MyBatis 是一个优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。在 MyBatis 中,配置数据库连接是非常重要的第一步。下面将详细介绍如何配置 MyBatis 的
今天小编给大家分享的是MyBatis批量查询、插入、更新、删除如何实现,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。
今天小编给大家分享的是Mybatis操作多数据源实现的方法,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获...
本篇文章和大家了解一下mybatis集成到spring的方式有哪些。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。1 前言1.1 集成spring前使用mybat...
今天小编给大家分享的是mybatis-plus分页查询的3种方法,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获...
本篇内容主要讲解“mybatis之BaseTypeHandler怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“mybatis...
这篇文章主要介绍了mybatisforeach怎么传两个参数的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇mybatisforeach怎...
这篇“MyBatis映射文件中parameterType与resultType怎么使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的...
这篇文章主要介绍“MyBatis怎么获取自动生成的键值”,在日常操作中,相信很多人在MyBatis怎么获取自动生成的键值问题上存在疑惑,小编查阅了各式资料,整理出
这篇文章主要讲解了“怎么去掉IntelliJIDEA中mybatis对应的xml文件警告”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入...
这篇文章主要介绍“MybatisPlus使用@TableId主键id自增长无效如何解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这...