MyBatis之手动映射

在一些简单的场景下,MyBatis 能够自动完成对象和数据库字段之间的映射,这时就不需要手动映射。

手动映射通常在以下情况下需要使用:

  1. 复杂查询或结果:当查询返回的结果结构与实体类不完全匹配,或者返回的结果需要进行复杂的处理时。
  2. 多表关联查询:当通过SQL进行多表联合查询时,返回的结果可能包含多个实体类的字段,这时需要手动映射结果到特定的对象。
  3. 非标准字段名:数据库的字段名与实体类属性名不一致,自动映射工具无法正确处理时。
  4. 部分字段映射:当查询的结果只需要映射到对象的部分字段时。

在MyBatis的XML文件中,我们可以通过<resultMap>来进行手动映射。这种方式适合需要映射复杂对象的情况,比如下面的用户和地址信息的场景。下面是如何在MyBatis的XML文件中编写手动映射的示例。

例子:手动映射实体类和SQL查询

1. 表结构

假设有两个表:useraddress,它们的关系是一对一(每个用户对应一个地址)。

User表

java 复制代码
CREATE TABLE user (
    id BIGINT PRIMARY KEY,
    name VARCHAR(50),
    email VARCHAR(100)
);

Address表

java 复制代码
CREATE TABLE address (
    id BIGINT PRIMARY KEY,
    user_id BIGINT,
    city VARCHAR(100),
    street VARCHAR(100),
    FOREIGN KEY (user_id) REFERENCES user(id)
);

2. 实体类

User实体类

java 复制代码
public class User {
    private Long id;
    private String name;
    private String email;
    private Address address;  // 对应用户的地址
    // Getters and Setters
}

Address实体类

java 复制代码
public class Address {
    private Long id;
    private String city;
    private String street;
    // Getters and Setters
}

3. 在XML中手动映射

MyBatis XML文件通常与Mapper接口文件对应。假设Mapper接口是UserMapper.java,XML文件命名为UserMapper.xml

XML文件内容如下:

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.example.mapper.UserMapper">

    <!-- 手动映射User和Address -->
    <resultMap id="UserResultMap" type="com.example.model.User">
        <!-- 映射User表的字段 -->
        <id property="id" column="userId" />
        <result property="name" column="name" />
        <result property="email" column="email" />
        
        <!-- 嵌套映射Address对象 -->
        <association property="address" javaType="com.example.model.Address">
            <id property="id" column="addressId" />
            <result property="city" column="city" />
            <result property="street" column="street" />
        </association>
    </resultMap>

    <!-- 查询用户及其地址 -->
    <select id="getUserWithAddress" parameterType="long" resultMap="UserResultMap">
        SELECT u.id AS userId, u.name, u.email, 
               a.id AS addressId, a.city, a.street
        FROM user u
        LEFT JOIN address a ON u.id = a.user_id
        WHERE u.id = #{userId}
    </select>

</mapper>
  • <resultMap>:用来定义如何将查询结果映射到Java对象。id用于标识主键字段,result用于映射普通字段。

  • <--column 数据库中的字段名--> <--property 实体类中对应的属性 该关键字可以省略... -->

  • <association>:用于嵌套映射复杂对象。在本例中,我们将User中的address字段映射到Address对象。

  • <select>:这是查询语句,parameterType="long"表示传入的参数类型是LongresultMap="UserResultMap"表示结果映射使用上面定义的UserResultMap

4. 详解解析

4.1 XML声明和<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.example.mapper.UserMapper">
  • <?xml version="1.0" encoding="UTF-8" ?>: 声明了XML的版本和编码。
  • <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">: 这是MyBatis的映射文件的DTD声明,用于校验映射文件的合法性。
  • <mapper>: 根元素,声明了Mapper接口的命名空间,namespace="com.example.mapper.UserMapper"表示此XML文件对应于UserMapper接口。MyBatis通过这个命名空间将SQL映射与接口方法进行关联。

4.2 手动映射用户和地址对象

XML 复制代码
<resultMap id="UserResultMap" type="com.example.model.User">
    <!-- 映射User表的字段 -->
    <id property="id" column="userId" />
    <result property="name" column="name" />
    <result property="email" column="email" />

    <!-- 嵌套映射Address对象 -->
    <association property="address" javaType="com.example.model.Address">
        <id property="id" column="addressId" />
        <result property="city" column="city" />
        <result property="street" column="street" />
    </association>
</resultMap>

resultMap

  • <resultMap>: 定义如何将查询结果映射到Java对象。在这里,id="UserResultMap"表示这个结果映射的名称,type="com.example.model.User"表示这个映射对应的是User类。
  • <id>: 映射主键。property="id"表示User对象的id属性,column="userId"表示数据库中的userId列。这一步将数据库中的userId映射到User类的id字段。
  • <result>: 映射普通字段。property="name"property="email"分别映射到数据库中的nameemail列。

嵌套映射Address

  • <association>: 用于将复杂的关联对象进行映射。在本例中,property="address"表示User对象中关联的Address对象,javaType="com.example.model.Address"表示映射到的Java类型是Address类。
  • <id><result>: 同样映射Address对象的属性。property="id"表示Addressid属性,column="addressId"表示查询结果中表示addressId的列。citystreet属性同理。

4.3 查询用户及其地址的SQL语句

XML 复制代码
<select id="getUserWithAddress" parameterType="long" resultMap="UserResultMap">
    SELECT u.id AS userId, u.name, u.email, 
           a.id AS addressId, a.city, a.street
    FROM user u
    LEFT JOIN address a ON u.id = a.user_id
    WHERE u.id = #{userId}
</select>

<select>元素

  • <select>: 定义SQL查询语句。id="getUserWithAddress"表示这个查询的名称,MyBatis会根据这个ID将它与Mapper接口中的方法进行关联。parameterType="long"表示传入的参数类型是Long类型,通常是用于传递userId
  • resultMap="UserResultMap": 指定查询结果的映射规则,使用前面定义的UserResultMap来将结果集映射到User对象和关联的Address对象。

SQL语句

  • SELECT u.id AS userId, u.name, u.email, a.id AS addressId, a.city, a.street: 这是具体的SQL查询语句,查询用户表user和地址表address中的字段,并为字段取别名以便与Java对象的字段匹配。

    • u.id AS userId: 将user表的id作为userId,用于映射User类的id字段。
    • a.id AS addressId: 将address表的id作为addressId,用于映射Address类的id字段。
  • FROM user u LEFT JOIN address a ON u.id = a.user_id: 从user表中查询,同时使用LEFT JOINaddress表进行关联,条件是u.id = a.user_id,即用户的id等于地址表中的user_id

  • WHERE u.id = #{userId}: 查询条件是用户的id等于传入的userId

4.4 整体流程

  1. 传入参数 : 当调用Mapper接口的getUserWithAddress(Long userId)方法时,userId会被传入SQL语句中的WHERE子句中。
  2. 执行查询 : MyBatis执行SELECT语句,查询用户和关联的地址信息。
  3. 结果映射 : 查询结果根据UserResultMap中的定义,映射到UserAddress对象的属性中。
  4. 返回结果 : 映射后的User对象(包含嵌套的Address对象)被返回。
相关推荐
AiFlutter4 分钟前
Java实现简单的搜索引擎
java·搜索引擎·mybatis
虚拟网络工程师16 分钟前
【网络系统管理】Centos7——配置主从mariadb服务器案例(下半部分)
运维·服务器·网络·数据库·mariadb
福如意如我心意24 分钟前
PostGres命令【常用维护,增删改查】
数据库·postgresql·psql
袁庭新36 分钟前
Cannal实现MySQL主从同步环境搭建
java·数据库·mysql·计算机·java程序员·袁庭新
爱学习的白杨树1 小时前
MySQL中有哪几种锁?
数据库·mysql
007php0071 小时前
GoZero 上传文件File到阿里云 OSS 报错及优化方案
服务器·开发语言·数据库·python·阿里云·架构·golang
晴天飛 雪1 小时前
Grafana监控PostgreSQL
数据库·postgresql·grafana
斗-匕1 小时前
Spring事务管理
数据库·spring·oracle
一行玩python2 小时前
SQLAlchemy,ORM的Python标杆!
开发语言·数据库·python·oracle
MXsoft6182 小时前
华为服务器(iBMC)硬件监控指标解读
大数据·运维·数据库