MyBatis-Plus ORM数据库和实体类映射方式

 更新时间:2025年01月20日 10:59:19   作者:Yan.love  
本文详细介绍了MyBatis-Plus(MP)在数据库和Java对象映射方面的功能,包括基本映射、主键生成策略、复杂映射(如嵌套对象和集合类型)以及自定义SQL的使用,MP通过丰富的注解和XML配置,简化了数据库操作,提高了开发效率

在开发中,数据库和 Java 对象的映射(ORM)是一个绕不开的话题,而 MyBatis-Plus(MP)作为一款优秀的 ORM 工具,帮我们简化了繁琐的数据库操作。本文将从数据库基础、表与实体映射、复杂对象映射、自定义 SQL 等角度,深入探讨 MP 的数据库映射功能。

一、数据库设计基本知识

在开始 ORM 映射之前,理解数据库设计的基本原则至关重要:

1. 索引

索引可以提高查询效率,例如主键索引、唯一索引、复合索引等。

在创建实体时,可以用注解标注需要索引的字段:

@TableField("username")
@TableIndex(type = IndexType.UNIQUE)
private String username;

2. 主键与外键

  • 主键:标识表中每一行记录的唯一性。
  • 外键:用来建立表与表之间的关系。

3. 范式

数据库范式(如第一范式、第三范式)是设计良好表结构的重要参考。

Tip: 保持表结构简单,但不妨碍业务扩展。

二、表与实体的映射关系

MP 提供了丰富的注解,帮助开发者高效完成数据库表与 Java 对象的映射。

1. 基本映射

MP 默认将表名与实体名直接映射,但我们可以通过注解自定义:

表名映射:使用 @TableName 注解将实体类与数据库表关联:

@TableName("user")
public class User {
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    @TableField("username")
    private String name;
}

字段名映射:数据库字段名通常为下划线风格,Java 属性名为驼峰风格。当字段名与属性名不一致时,MP 默认自动处理这种映射,也可以通过 @TableField 自定义:

@TableField("email_address")
private String emailAddress;

2. 自定义主键生成策略

主键生成是 ORM 映射中重要的一环,当往数据库添加字段的时候,此id会根据指定的主键生成策略来进行生成对应的值。MP 支持多种主键生成策略:

IdType.AUTO

  • 适用于主键为自增类型(如 MySQL 的 AUTO_INCREMENT
  • 在插入数据时,不需要为主键赋值,由数据库根据自增策略生成。
  • 此策略仅在数据库支持自增主键的情况下有效,需要在数据库中保证主键是自增的。

IdType.ASSIGN_ID

  • MyBatis-Plus 默认的主键生成策略,使用 雪花算法 生成全局唯一 ID。
  • 在插入数据时,MP 自动生成主键值,并在 SQL 中直接插入该值。
  • 数据库表的主键类型为 BIGINT,需要全局唯一标识符。

IdType.INPUT

  • 手动输入主键值
  • 需要在插入数据前手动设置主键值,否则插入操作将失败。
  • 适用于特定业务场景(如主键由外部系统生成)。

示例:

在实体类中通过注解设置:

@TableId(value = "id", type = IdType.AUTO)
private Long id;

全局设置主键策略(application.yaml 配置文件中)

mybatis-plus:
  global-config:
    db-config:
      id-type: ASSIGN_ID  # 全局默认使用雪花算法
      # 可选值:
      # AUTO: 数据库自增
      # NONE: 无状态
      # INPUT: 手动输入
      # ASSIGN_ID: 雪花算法
      # ASSIGN_UUID: UUID

三、XML 中配置复杂映射

1. 基本数据类型映射

对于普通表字段到实体属性的映射,MP 提供了简单直观的方式。

通过 resultMap 解决复杂结果集的映射问题。

指定了id之后,如果查询数据中包含了多个id的值,会自动合并,映射为一个对象集合

a. 基本映射规则

MP 默认遵循数据库字段名和实体类属性名之间的映射规则

  • 数据库字段名:下划线命名。
  • Java 属性名:驼峰命名。

示例表结构(user 表):

CREATE TABLE user (
    id BIGINT PRIMARY KEY,
    username VARCHAR(50),
    age INT
);

实体类定义:

@Data
public class User {
    private Long id;          // 对应数据库字段 id
    private String username;  // 对应数据库字段 username
    private Integer age;      // 对应数据库字段 age
}

b. 自定义字段映射

通过 column 属性来指定表字段

<resultMap id="userMap" type="User">
    <id property="id" column="id"/>
    <result property="username" column="user_name"/>
    <result property="age" column="age"/>
</resultMap>

2. 嵌套对象映射

嵌套对象映射用于处理对象属性本身是另一个复杂对象的场景,例如主表与子表关联。

a. 表和实体类

假设有以下表结构

user表:

CREATE TABLE user (
     id BIGINT PRIMARY KEY,
     name VARCHAR(50)
 ); 

address表:

    CREATE TABLE address (
      id BIGINT PRIMARY KEY,
      user_id BIGINT,
      city VARCHAR(50),
      FOREIGN KEY (user_id) REFERENCES user(id)
    );

实体类定义:

@Data
public class User {
    private Long id;
    private String name;
    private Address address; // 嵌套对象
}

@Data
public class Address {
    private Long id;
    private Long userId;
    private String city;
}

b. XML 映射

在 XML 文件中通过 <association> 定义嵌套对象映射:

<resultMap id="userWithAddressMap" type="User">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <association property="address" javaType="Address">
        <id property="id" column="address_id"/>
        <result property="city" column="city"/>
    </association>
</resultMap>

<select id="selectUserWithAddress" resultMap="userWithAddressMap">
    SELECT u.id, u.name, a.id AS address_id, a.city
    FROM user u
    LEFT JOIN address a ON u.id = a.user_id
</select>

3. 集合类型映射

当查询结果中存在一个字段包含 多个值(例如多个标签 tag),并且在实体类中将该字段指定为 集合类型(如 List<String>),MyBatis-Plus 会根据配置自动将这些值合并并映射为集合。

这种场景常见于 一对多多对多 的查询中,主要通过 <collection> 元素 实现。

a. 基本示例

① 假设有以下数据:

article_tag

article_idtag
1Spring
1MyBatis
2Java

② 实体类定义

public class Article {
    private Long id;               // 文章 ID
    private String title;          // 文章标题
    private List<String> tags;     // 标签集合
}

③ Mapper 配置(XML 映射文件)

使用 <collection> 将多行数据的 tag 字段自动映射为一个集合:

<resultMap id="ArticleResultMap" type="com.example.Article">
    <id property="id" column="article_id" />
    <result property="title" column="title" />
    <collection property="tags" ofType="java.lang.String">
        <result column="tag" />
    </collection>
</resultMap>

<select id="selectArticlesWithTags" resultMap="ArticleResultMap">
    SELECT 
        a.id AS article_id, 
        a.title, 
        t.tag 
    FROM 
        article a
    LEFT JOIN 
        article_tag t 
    ON 
        a.id = t.article_id
</select>

④ 查询结果

List<Article> articles = articleMapper.selectArticlesWithTags();

假设查询结果为:

[
  {
    "id": 1,
    "title": "学习 MyBatis",
    "tags": ["Spring", "MyBatis"]
  },
  {
    "id": 2,
    "title": "Java 基础",
    "tags": ["Java"]
  }
]

b. 对象类型集合

以用户为例和订单表为例:

① 表和实体类

假设有以下表结构

user表:

CREATE TABLE user (
    id BIGINT PRIMARY KEY,
    name VARCHAR(50)
);

order表:

CREATE TABLE order (
    id BIGINT PRIMARY KEY,
    user_id BIGINT,
    order_number VARCHAR(50),
    FOREIGN KEY (user_id) REFERENCES user(id)
);

实体类定义:

@Data
public class User {
    private Long id;
    private String name;
    private List<Order> orders; // 集合类型
}

@Data
public class Order {
    private Long id;
    private Long userId;
    private String orderNumber;
}

XML 映射

在 XML 文件中通过 <collection> 定义集合映射:

<resultMap id="userWithOrdersMap" type="User">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <collection property="orders" ofType="Order">
        <id property="id" column="order_id"/>
        <result property="orderNumber" column="order_number"/>
    </collection>
</resultMap>

<select id="selectUserWithOrders" resultMap="userWithOrdersMap">
    SELECT u.id, u.name, o.id AS order_id, o.order_number
    FROM user u
    LEFT JOIN order o ON u.id = o.user_id
</select>

【注意事项】

  • <collection> 的 ofType 属性指定集合中元素的类型。
  • 确保 SQL 查询中包含子表数据,否则集合为空。

四、自定义 SQL

MP 提供了两种自定义 SQL 的方式:XML 文件注解方式

1. 使用注解自定义 SQL

Mapper 接口中直接使用注解书写简单 SQL:

@Mapper
public interface UserMapper extends BaseMapper<User> {
    @Select("SELECT * FROM user WHERE name = #{name}")
    User findByName(@Param("name") String name);
}
  • 优点:简洁、轻量化。
  • 缺点:不适合复杂查询。

2. 使用 XML 文件自定义 SQL

对于复杂 SQL,建议使用 XML 文件。MP 通过 Mapper 文件与 XML 配置绑定:

UserMapper.java

@Mapper
public interface UserMapper extends BaseMapper<User> {
    User selectUserWithOrders(Long userId);
}

UserMapper.xml

<resultMap id="userResultMap" type="User">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <collection property="orders" ofType="Order">
        <id property="id" column="order_id"/>
        <result property="orderNumber" column="order_number"/>
    </collection>
</resultMap>

<mapper namespace="com.example.mapper.UserMapper">
    <select id="selectUserWithOrders" resultType="User">
        SELECT u.*, o.*
        FROM user u
        LEFT JOIN order o ON u.id = o.user_id
        WHERE u.id = #{userId}
    </select>
</mapper>

五、写在最后

总结:

  • MP 将实体类与数据库表映射打通,使得开发效率提升。
  • 对于复杂场景,XML 自定义 SQL 是不可或缺的利器。
  • 主键生成字段映射等基础功能覆盖面广,足够应对大多数项目需求。

建议:

  • 优先使用 MP 提供的内置方法,减少代码冗余。
  • 复杂业务逻辑时,灵活使用自定义 SQL(尤其是 XML 文件)。
  • 对于关联查询,合理使用 resultMap嵌套映射

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 超级详细的Java安装教程(Mac版)

    超级详细的Java安装教程(Mac版)

    Java是一种广泛使用的编程语言,可用于开发各种类型的应用程序,这篇文章主要给大家介绍了关于Mac系统下Java安装的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-10-10
  • Kotlin 语言中调用 JavaScript 方法实例详解

    Kotlin 语言中调用 JavaScript 方法实例详解

    这篇文章主要介绍了Kotlin 语言中调用 JavaScript 方法实例详解的相关资料,需要的朋友可以参考下
    2017-06-06
  • Spring依赖注入中的@Resource与@Autowired详解

    Spring依赖注入中的@Resource与@Autowired详解

    这篇文章主要介绍了Spring依赖注入中的@Resource与@Autowired详解,提到Spring依赖注入,大家最先想到应该是@Resource和@Autowired,对于Spring为什么要支持两个这么类似的注解却未提到,属于知其然而不知其所以然,本文就来做详细讲解,需要的朋友可以参考下
    2023-09-09
  • java返回的List进行add操作报错

    java返回的List进行add操作报错

    本文主要介绍了java返回的List进行add操作报错,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • Java毕业设计实战之校园一卡通系统的实现

    Java毕业设计实战之校园一卡通系统的实现

    这是一个使用了java+Springboot+Maven+mybatis+Vue+mysql+wd开发的校园一卡通系统,是一个毕业设计的实战练习,具有校园一卡通系统该有的所有功能,感兴趣的朋友快来看看吧
    2022-01-01
  • 基于ComponentScan注解的扫描范围及源码解析

    基于ComponentScan注解的扫描范围及源码解析

    这篇文章主要介绍了基于ComponentScan注解的扫描范围及源码解析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • 一种新的日期处理方式之JavaScript Temporal API

    一种新的日期处理方式之JavaScript Temporal API

    JavaScript Temporal API是一种为Web开发人员提供了一种新的处理日期和时间数据类型的方式。它的目的是使操作日期和时间更加简单和可靠,而且不用担心历史时区问题或全球化协调时间(UTC)之类的问题,感兴趣的同学可以参考阅读
    2023-05-05
  • Springboot MDC+logback实现日志追踪的方法

    Springboot MDC+logback实现日志追踪的方法

    MDC(Mapped Diagnostic Contexts)映射诊断上下文,该特征是logback提供的一种方便在多线程条件下的记录日志的功能,这篇文章主要介绍了Springboot MDC+logback实现日志追踪的方法,需要的朋友可以参考下
    2024-04-04
  • SpringMVC上传文件的三种实现方式

    SpringMVC上传文件的三种实现方式

    本篇文章主要介绍了SpringMVC上传文件的三种实现方式,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • SpringMvc/SpringBoot HTTP通信加解密的实现

    SpringMvc/SpringBoot HTTP通信加解密的实现

    这篇文章主要介绍了SpringMvc/SpringBoot HTTP通信加解密的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08

最新评论