Mybatis中ResultMap解决属性名和数据库字段名不一致问题

目录
  • 前言
  • 1. 字段名不一致
    • 解决方法:
      • 第一种方式: 起别名
      • 第二种方式: 结果集映射 resultMap
  • 2. 多对一处理
  • 3. 一对多处理
  • 小结

前言

我们Pojo类的属性名和数据库中的字段名不一致的现象时有发生,简单的情况我们可以开启驼峰命名法解决大小写问题,但是遇到其它非大小写问题,我们就不得不使用Mybatis中的结果集映射resultMap。

1. 字段名不一致

数据库中的字段

我们项目中实体类的字段

public class User {

    private int id;
    private String name;
    private String password;

解决方法:

第一种方式: 起别名

pwd as password

<select id="getUserById" parameterType="int" resultType="com.gs.pojo.User">
    select id,name,pwd as password from user1 where id = #{id};
</select>

第二种方式: 结果集映射 resultMap

使用resultMap匹配pojo类中属性名与数据库中字段的值。
其中column为数据库中的字段,property为实体类中的属性

<!--结果集映射-->
<resultMap id="UserMap" type="user">
    <!--column数据库中的字段,property实体类中的属性-->
    <result column="id" property="id"/>
    <result column="name" property="name"/>
    <result column="pwd" property="password"/>
</resultMap>

<select id="getUserById" parameterType="int" resultMap="UserMap">
    select * from user1 where id = #{id};
</select>

官方文档有这么一段话:

  • resultMap元素是MyBatis中最重要强大的元素
  • ResultMap的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
  • ResultMap的优秀之处在于你完全可以不用显示的配置字段名已经相同的属性

根据官方文档,上面的结果集映射可以简化为:

<!--结果集映射-->
<resultMap id="UserMap" type="user">
    <!--column数据库中的字段,property实体类中的属性-->

    <result column="pwd" property="password"/>
</resultMap>

<select id="getUserById" parameterType="int" resultMap="UserMap">
    select * from user1 where id = #{id};
</select>

2. 多对一处理

上面讲述的只是普通字段名不一致的问题,使用结果集映射解决相对简单。而在Mybatis中关于使用结果集映射解决的问题比较出名的有多对一的处理和一对多的处理(这两种问题是相对而言的)

我们生活中有很多相关的例子,这里以老师和学生为例,对于学生而言,多个学生拥有一个共同的老师,这属于多对一问题;对于老师而言,一个老师拥有多个学生,这又是一个一对多的问题。

相关解析:
对于学生而言,属于关联现象,多个老师关联一个老师 (多对一)
对于老师而言,属于集合现象, 一个老师拥有很多学生(一对多)

测试环境搭建;
[1] 建立一个老师表和学生表

CREATE TABLE `teacher`(

   `id` INT(10) NOT NULL,
   `name` VARCHAR(30) DEFAULT NULL,
   PRIMARY KEY (`id`)
)ENGINE = INNODB DEFAULT CHARSET=utf8

INSERT INTO teacher(`id`,`name`) VALUES(1,'zs');

CREATE TABLE `student`(

   `id` INT(10) NOT NULL,
   `name` VARCHAR(30) DEFAULT NULL,
   `tid` INT(10) DEFAULT NULL,
    PRIMARY KEY(`id`),
    KEY `fktid` (`tid`),
    CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher`(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO `student`(`id`,`name`,`tid`) VALUES('1','小明','1');
INSERT INTO `student`(`id`,`name`,`tid`) VALUES('2','小红','1');
INSERT INTO `student`(`id`,`name`,`tid`) VALUES('3','小张','1');
INSERT INTO `student`(`id`,`name`,`tid`) VALUES('4','小李','1');
INSERT INTO `student`(`id`,`name`,`tid`) VALUES('5','小工','1');

[2] 新建一个Maven项目,导入相关依赖,并编写实体类及其映射
搭建后项目目录为:

<1> 导入依赖,并解决打包问题

 <!--导入依赖-->
    <dependencies>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
        </dependency>
    </dependencies>

    <!--解决导出项目时resources的xml未打包问题-->
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

<2> 编写数据库配置文件 db.properties

driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8
username = root

<3> 编写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 resource="db.properties"/>

   <!-- <settings>
        &lt;!&ndash;标准的日志工厂实现&ndash;&gt;
        &lt;!&ndash;<setting name="logImpl" value="STDOUT_LOGGING"/>&ndash;&gt;
        <setting name="logImpl" value="LOG4J"/>
    </settings>-->

    <!--可以给实体类起别名-->
    <typeAliases>
       <package name="com.gs.pojo"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
            </dataSource>
        </environment>

    </environments>

    <mappers>
        <mapper resource="com/gs/dao/TeacherMapper.xml"/>
        <mapper resource="com/gs/dao/StudentMapper.xml"/>
        <!--<mapper class="com.com.com.gs.dao.TeacherMapper"/>
        <mapper class="com.com.com.gs.dao.StudentMapper"/>-->
    </mappers>

</configuration>

<4> 编写实体类
这里的Student类中有一个老师的字段,这正是与我们数据库中不一致的地方,也是这次问题解决的重点
Student.class

package com.gs.pojo;

import lombok.Data;

/**
 * @Auther: Gs
 * @Date: 2020/6/9
 * @Description: com.com.com.gs.pojo
 * @version: 1.0
 */
@Data
public class Student {

    private int id;
    private String name;
    //组合进来一个老师
    private Teacher teacher;

}

Teacher.class

package com.gs.pojo;

import lombok.Data;

/**
 * @Auther: Gs
 * @Date: 2020/6/9
 * @Description: com.com.com.gs.pojo
 * @version: 1.0
 */
@Data
public class Teacher {

    private int id;
    private String name;

}

<5> 编写接口 StudentMapper

public interface StudentMapper {

    //查询所有的学生信息,以及对应的的老师的信息
    public List<Student> getStudent();
}

<6> 使用resultMap解决问题

[1] 按结果嵌套查询 使用association字段来匹配结果集中Teacher中的字段属性

<!--按照结果嵌套处理-->
<select id="getStudent" resultMap="studentMapper2">
    select s.id sid, s.name sname, t.name tname
    from student s, teacher t
    where s.tid = t.id
</select>

<resultMap id="studentMapper2" type="student">
    <result property="id" column="sid"/>
    <result property="name" column="sname"/>
    <association property="teacher" javaType="Teacher">
        <result property="name" column="tname"/>
    </association>
</resultMap>

解析:一开始看这sql语句肯定很绕,我们先从原生的sql语句出发,编写出能联表查询的语句(因为学生类里有老师这个实体属性)
这里我们使用别名以及联表查询得到学号,学生姓名,老师姓名,不难发现我们使用简单的reultType已经不能解决这个多属性问题(resultType适合解决单一实体类,字段名和数据库属性一一对应的情况),所以我们想到使用结果集映射 resultMap.

select s.id sid, s.name sname, t.name tname
   from student s, teacher t
   where s.tid = t.id

resultMap中前两项的字段名和属性名比较好映射,直接是学生的id,学生的姓名,可是最后一项的属性时一个Teacher对象,所以我们必须使用关联association 来嵌套老师这个实体类的属性。相关语句为:

<association property="teacher" javaType="Teacher">
    <result property="name" column="tname"/>
</association>

那么完整的隐射语句为:

<resultMap id="studentMapper2" type="student">
    <result property="id" column="sid"/>
    <result property="name" column="sname"/>
    <association property="teacher" javaType="Teacher">
        <result property="name" column="tname"/>
    </association>
</resultMap>

最后我们再把这两个语句拼接就能得到我们最终的语句了。

[2] 按照查询嵌套处理 (理解起来相对复杂)

<!--思路: 1.查询所有的学生信息
          2.根据查询出来的学生的tid,寻找对应的老师 子查询
-->

<select id="getStudent" resultMap="studentMapper">
    select * from student;
</select>
<resultMap id="studentMapper" type="student">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <!--复杂的属性,我们需要单独处理 对象: association  集合: collection -->
    <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>

<select id="getTeacher" resultType="Teacher">
    select * from teacher where id = #{id};
</select>

解析:看着语句更加晕了,这其实相当于我们原生Sql的子查询,这里分三步走,把原本的结果集在通过查询进行封装。
<1> 编写简单的学生查询

<select id="getStudent" resultMap="studentMapper">
    select * from student;
</select>

<2> 完成相关实体类属性和数据库字段的映射,前两个依旧简单,关键还是Teacher这个实体类,这次我们不嵌套属性,而是通过一次子查询解决问题 (property对应实体类属性,column对应数据库名称,javaType标明类型,select表示使用查询的方法)

  <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>

这里使用 getTeacher的方法获取新的属性值

<select id="getTeacher" resultType="Teacher">
    select * from teacher where id = #{id};
</select>

完整的映射

<resultMap id="studentMapper" type="student">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <!--复杂的属性,我们需要单独处理 对象: association  集合: collection -->
    <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>

最后,我们把这三句sql进行拼装,就能得到我们上面最终的结果了。

3. 一对多处理

同样是上面的例子,对老师而言,就是一对多的关系
[1] 环境搭建和上面的一样
[2] 测试的实体类的变化
Student

@Data
public class Student {
	//学生id
    private int id;
    //学生姓名
    private String name;
    //教师id
    private int tid;
}

Teacher

@Data
public class Teacher {

    private int id;
    private String name;

    //一个老师有多个学生
    private List<Student> students;

}

[3] 业务需求:获取指定老师下所有学生及老师自身的信息
<1> 编写接口

//获取指定老师下所有学生及老师的信息
Teacher getTeacher(@Param("tid") int id);

<2> 解决方式依旧是两种,一种是按结果嵌套查询(即所谓的连接查询),另外一种是按照查询嵌套处理(即所谓的子查询)
第一种方式:按结果嵌套查询

编写连接查询的sql语句

<!--按结果嵌套查询-->
<select id="getTeacher" resultMap="teacherMap">
    select s.id sid, s.name sname, t.id tid, t.name tname from student s, teacher t
    where s.tid = t.id and  t.id = #{tid}
</select>

通过结果集映射找到相应的属性(由于是一对多关系,所以使用集合类型 collection)

<resultMap id="teacherMap" type="teacher">
    <result property="id" column="tid"/>
    <result property="name" column="tname"/>
    <!--复杂的属性:我们需要单独处理对象, 对象:association 集合:collection
    javaType="" 指定属性类型
    ofType 指定属性中的泛型类型
    -->
    <collection property="students" ofType="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="tid" column="tid"/>
    </collection>
</resultMap>

相关解析:
复杂的属性:我们需要单独处理对象, 多对一时使用 association,一对多是使用collection;
若是普通的pojo类使用 javaType="" 指定属性类型,若是泛型类型则要使用ofType 指定属性中的泛型类型
3) 我们拼接一下上面两段代码即得到我们的结果

<!--按结果嵌套查询-->
<select id="getTeacher" resultMap="teacherMap">
    select s.id sid, s.name sname, t.id tid, t.name tname from student s, teacher t
    where s.tid = t.id and  t.id = #{tid}
</select>
<resultMap id="teacherMap" type="teacher">
    <result property="id" column="tid"/>
    <result property="name" column="tname"/>
    <!--复杂的属性:我们需要单独处理对象, 对象:association 集合:collection
    javaType="" 指定属性类型
    ofType 指定属性中的泛型类型
    -->
    <collection property="students" ofType="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="tid" column="tid"/>
    </collection>
</resultMap>

第二种方式:按照查询嵌套处理

使用子查询进行拼接
<1> 先查出指定老师的信息

<!--子查询-->
<select id="getTeacher" resultMap="teacherMap2">
    select * from teacher where id = #{tid}
</select>

<2> 由于查询的信息里有学生对象信息,所以得进行结果集映射

<resultMap id="teacherMap2" type="Teacher">
    <result property="id" column="id"/>
    <collection property="students" column="id" javaType="ArrayList" ofType="Student" select="getStudent"/>
</resultMap>

解析:

<collection property="students" column="id" javaType="ArrayList" ofType="Student" select="getStudent"/>

property表明要查询的实体类属性名,javaType表明查询的类型,ofType表明泛型的类型,select表明使用查询的方式,这里比较疑惑的应该是column的值,它对应的是数据库中的列,那它应该使用什么呢,我们不难发现,我们要查询的是老师下的所有学生,而学生表示通过老师id进行关联的,那么它对应的值应该是数据库的教师id的列名
<3> 最后编写通过老师id查询学生的方法.getStudent

<select id="getStudent" resultType="Student">
    select * from student where tid=#{id}
</select>

<4> 最后我们把上面的代码块进行拼接就能满足我们的业务需求了。

<!-- =============================== -->
<!--子查询-->
<select id="getTeacher" resultMap="teacherMap2">
    select * from teacher where id = #{tid}
</select>
<resultMap id="teacherMap2" type="Teacher">
    <result property="id" column="id"/>
    <collection property="students" column="id" javaType="ArrayList" ofType="Student" select="getStudent"/>
</resultMap>
<select id="getStudent" resultType="Student">
    select * from student where tid=#{id}
</select>

小结

解决属性名不一致的问题大体上分为三种情况。简单的名字不同,类型相同我们可以起别名解决。对于名字不同,类型也不同,我们只能使用结果集映射解决,这种方式又分为两种情况,一种是多对一,一种是一对多,我们在解决多对一时,可以联想学生和老师的关系,多个学生关联一个老师,那么我们使用association(关联)这个关键词,而反过来,一个老师下有多个学生,属于集合关系,那么我们可以使用collection(集合)。

到此这篇关于Mybatis中ResultMap解决属性名和数据库字段名不一致问题的文章就介绍到这了,更多相关Mybatis 属性名和数据库字段名不一致内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • MyBatis查询时属性名和字段名不一致问题的解决方法

    问题 当我们数据库中的字段和实体类中的字段不一致的时候,查询会出问题 数据库字段是 pwd id name pwd 1 张三 123456 2 李四 123456 3 王五 123456 4 赵六 123456 实体类字段是 password public class User { private int id; private String name; private String password; } 查出来结果发现, password 是 null User{id=1, name='张三

  • Mybatis中ResultMap解决属性名和数据库字段名不一致问题

    目录 前言 1. 字段名不一致 解决方法: 第一种方式: 起别名 第二种方式: 结果集映射 resultMap 2. 多对一处理 3. 一对多处理 小结 前言 我们Pojo类的属性名和数据库中的字段名不一致的现象时有发生,简单的情况我们可以开启驼峰命名法解决大小写问题,但是遇到其它非大小写问题,我们就不得不使用Mybatis中的结果集映射resultMap. 1. 字段名不一致 数据库中的字段 我们项目中实体类的字段 public class User { private int id; pri

  • Mybatis中resultMap的Colum和property属性详解

    目录 resultMap的Colum和property属性 1: resultMap标签 2:使用情况 2.1 简单查询 2.2 一对一 2.3 一对多 resultMap对column和property的理解 select元素有很多属性(这里说用的比较多的) 什么时候我们知道使用resultMap,什么时候又使用resultType呢? 最后说下 resultMap的Colum和property属性 1: resultMap标签 当我们的数据库字段与实体类的属性不一致时,就需要使用该标签进行一

  • Mybatis中实体类属性与数据列表间映射方法介绍

    Mybatis不像Hibernate中那么自动化,通过@Column注解或者直接使用实体类的属性名作为数据列名,而是需要自己指定实体类属性和 数据表中列名之间的映射关系,这一点让用惯了Hibernate的人很不习惯,所幸经过探索找到了建立映射关系的三种办法,其中总也有比较 简单的. 首先先定义一个实体类,如下: public class User implements Serializable { private Integer userId; private String userName;

  • mybatis中resultMap 标签的使用教程

    MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身,而不需要花费精力去处理例如注册驱动.创建connection.创建statement.手动设置参数.结果集检索等jdbc繁杂的过程代码. MyBatis特点: 1.开源的优秀持久层框架 2.SQL语句与代码分离 3.面向配置的编程 4.良好支持复杂数据映射 5.动态SQL resultMap 标签: 用来描述如何从数据库结果集中来加载对象 (敲黑板!!)主管数据库的字段和实体类属性的匹配,

  • Mybatis中resultMap的使用总结

    Mybatis的介绍以及使用:http://www.mybatis.org/mybatis-3/zh/index.html resultMap是Mybatis最强大的元素,它可以将查询到的复杂数据(比如查询到几个表中数据)映射到一个结果集当中. resultMap包含的元素: <!--column不做限制,可以为任意表的字段,而property须为type 定义的pojo属性--> <resultMap id="唯一的标识" type="映射的pojo对象&

  • Java Mybatis使用resultMap时,属性赋值顺序错误的巨坑

    目录 Mybatis使用resultMap属性赋值顺序错误 ids是后加入的字段 resultMap中是这样写的 解决办法 Mybatis使用resultMap时需注意 Mybatis使用resultMap属性赋值顺序错误 今天发现个坑,新建的表使用生成工具生成的mapper文件和实体类后,发现少了个字段就又手动加了下,结果发现一个问题 ids是后加入的字段 @Data @Builder public class QueryRecordPo {        //若干其他属性....     p

  • MyBatis中resultMap和resultType的区别详解

    总结 基本映射 :(resultType)使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功.(数据库,实体,查询字段,这些全部都得一一对应)高级映射 :(resultMap) 如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系.(高级映射,字段名称可以不一致,通过映射来实现 resultType和resultMap功能类似 ,都是返回对象信息 ,但是resultMap要更强大一些

  • Mybatis中resultMap标签和sql标签的设置方式

    目录 resultMap标签和sql标签的设置 1.项目目录 2.数据库中的表的信息 3.配置文件的信息 4.User类 5.IUserDao接口 6.MybatisTest 7.运行结果 resultMap标签的使用规则 自定义结果映射规则 association联合查询 使用association进行分布查询 collection分步查询 resultMap标签和sql标签的设置 1.项目目录 2.数据库中的表的信息 3.配置文件的信息 1.SqlMapConfig.xml文件 <?xml

  • asp.net获取SQL所有数据库名、所有表名、所有字段名

    1.获取所有数据库名: SELECT Name FROM Master..SysDatabases ORDER BY Name 2.获取所有表名: SELECT Name FROM DatabaseName..SysObjects Where XType='U' ORDER BY Name XType='U':表示所有用户表; XType='S':表示所有系统表; 3.获取所有字段名: SELECT Name FROM SysColumns WHERE id=Object_Id('TableNa

  • SQLSERVER查询所有数据库名,表名,和字段名的语句

    1.获取所有数据库名: SELECT Name FROM Master..SysDatabases ORDER BY Name 2.获取所有表名: SELECT Name FROM DatabaseName..SysObjects Where XType='U' ORDER BY Name XType='U':表示所有用户表; XType='S':表示所有系统表; 3.获取所有字段名: SELECT Name FROM SysColumns WHERE id=Object_Id('TableNa

随机推荐