在开发中,数据库和 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_id | tag |
---|---|
1 | spring |
1 | mybatis |
2 | java |
② 实体类定义
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
和嵌套映射。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论