薛之谦_头像
Java 持久层实战:MyBatis 与 MyBatis-Plus 详细用法对比封面图

Java 持久层实战:MyBatis 与 MyBatis-Plus 详细用法对比

1. 引言

在 Java 后端开发中,持久层框架的选择直接影响开发效率与代码可维护性。MyBatis 以「SQL 可控、映射灵活」著称,而 MyBatis-Plus 在 MyBatis 之上做了增强,提供了大量开箱即用的 CRUD 能力。

本文从零开始,分别演示 原生 MyBatis 与 MyBatis-Plus 的详细用法,并在最后给出两者的对比与选型建议。全文基于以下版本:

组件版本
JDK17
Spring Boot3.2.x
MyBatis Spring Boot Starter3.0.3
MyBatis-Plus Spring Boot3 Starter3.5.5
MySQL8.0

2. 环境准备

2.1 建表语句

先准备一张用户表,后续两种方案都基于它演示:

CREATE TABLE `sys_user` (
  `id`        BIGINT       NOT NULL AUTO_INCREMENT COMMENT '主键',
  `username`  VARCHAR(64)  NOT NULL COMMENT '用户名',
  `password`  VARCHAR(128) NOT NULL COMMENT '密码',
  `age`       INT          DEFAULT NULL COMMENT '年龄',
  `email`     VARCHAR(128) DEFAULT NULL COMMENT '邮箱',
  `deleted`   TINYINT      NOT NULL DEFAULT 0 COMMENT '逻辑删除:0-未删除 1-已删除',
  `create_time` DATETIME   DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` DATETIME   DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

2.2 公共配置

application.yml 中的数据库连接配置:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

3. 原生 MyBatis 详细用法

3.1 引入依赖

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>3.0.3</version>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

3.2 实体类

package com.example.demo.entity;

import java.time.LocalDateTime;

public class SysUser {

    private Long id;
    private String username;
    private String password;
    private Integer age;
    private String email;
    private Integer deleted;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;

    // 省略 getter / setter,实际项目可用 Lombok 的 @Data
}

3.3 Mapper 接口

MyBatis 的 Mapper 接口只声明方法,SQL 写在 XML 或注解中:

package com.example.demo.mapper;

import com.example.demo.entity.SysUser;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

@Mapper
public interface SysUserMapper {

    int insert(SysUser user);

    int updateById(SysUser user);

    int deleteById(@Param("id") Long id);

    SysUser selectById(@Param("id") Long id);

    List<SysUser> selectList(@Param("username") String username,
                             @Param("minAge") Integer minAge);
}

3.4 XML 映射文件

在 src/main/resources/mapper/SysUserMapper.xml 中编写 SQL:

<?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.demo.mapper.SysUserMapper">

    <resultMap id="BaseResultMap" type="com.example.demo.entity.SysUser">
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="age" property="age"/>
        <result column="email" property="email"/>
        <result column="deleted" property="deleted"/>
        <result column="create_time" property="createTime"/>
        <result column="update_time" property="updateTime"/>
    </resultMap>

    <sql id="Base_Column_List">
        id, username, password, age, email, deleted, create_time, update_time
    </sql>

    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO sys_user (username, password, age, email)
        VALUES (#{username}, #{password}, #{age}, #{email})
    </insert>

    <update id="updateById">
        UPDATE sys_user
        <set>
            <if test="username != null">username = #{username},</if>
            <if test="password != null">password = #{password},</if>
            <if test="age != null">age = #{age},</if>
            <if test="email != null">email = #{email},</if>
        </set>
        WHERE id = #{id}
    </update>

    <delete id="deleteById">
        DELETE FROM sys_user WHERE id = #{id}
    </delete>

    <select id="selectById" resultMap="BaseResultMap">
        SELECT <include refid="Base_Column_List"/>
        FROM sys_user
        WHERE id = #{id}
    </select>

    <select id="selectList" resultMap="BaseResultMap">
        SELECT <include refid="Base_Column_List"/>
        FROM sys_user
        <where>
            <if test="username != null and username != ''">
                AND username LIKE CONCAT('%', #{username}, '%')
            </if>
            <if test="minAge != null">
                AND age &gt;= #{minAge}
            </if>
        </where>
        ORDER BY id DESC
    </select>

</mapper>

同时在 application.yml 中指定映射文件位置:

mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.example.demo.entity
  configuration:
    map-underscore-to-camel-case: true

3.5 注解方式(简单 SQL 可选)

对于简单 SQL,也可以直接用注解,省去 XML:

@Mapper
public interface SysUserAnnotationMapper {

    @Select("SELECT * FROM sys_user WHERE id = #{id}")
    SysUser selectById(@Param("id") Long id);

    @Insert("INSERT INTO sys_user(username, password, age) VALUES(#{username}, #{password}, #{age})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insert(SysUser user);
}

3.6 动态 SQL 常用标签

MyBatis 的强大之处在于动态 SQL,常用标签如下:

  • <if>:条件判断
  • <where>:自动处理 AND/OR 前缀
  • <set>:自动处理更新语句末尾逗号
  • <foreach>:遍历集合,常用于 IN 查询
  • <choose>/<when>/<otherwise>:多分支选择

<foreach> 示例:

<select id="selectByIds" resultMap="BaseResultMap">
    SELECT <include refid="Base_Column_List"/>
    FROM sys_user
    WHERE id IN
    <foreach collection="ids" item="id" open="(" separator="," close=")">
        #{id}
    </foreach>
</select>

3.7 事务与使用示例

@Service
public class UserService {

    private final SysUserMapper userMapper;

    public UserService(SysUserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Transactional(rollbackFor = Exception.class)
    public SysUser createUser(SysUser user) {
        userMapper.insert(user);
        return user;
    }

    public List<SysUser> search(String username, Integer minAge) {
        return userMapper.selectList(username, minAge);
    }
}

4. MyBatis-Plus 详细用法

4.1 引入依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
    <version>3.5.5</version>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

注意:Spring Boot 3 必须使用 mybatis-plus-spring-boot3-starter,Spring Boot 2 使用 mybatis-plus-boot-starter。

4.2 实体类与注解

MyBatis-Plus 通过注解把实体与表结构关联起来:

package com.example.demo.entity;

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;

import java.time.LocalDateTime;

@Data
@TableName("sys_user")
public class SysUser {

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

    private String username;

    private String password;

    private Integer age;

    private String email;

    @TableLogic
    private Integer deleted;

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
}

常用注解说明:

注解作用
@TableName指定表名
@TableId指定主键及生成策略(AUTO/ASSIGN_ID/INPUT 等)
@TableField指定字段名、填充策略、是否参与查询等
@TableLogic标记逻辑删除字段
@Version乐观锁版本号字段

4.3 Mapper 接口

只需继承 BaseMapper<T>,即可获得一整套 CRUD 方法:

package com.example.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.SysUser;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface SysUserMapper extends BaseMapper<SysUser> {
    // 无需写任何方法即可使用 insert/deleteById/updateById/selectById/selectList 等
}

4.4 基础 CRUD 用法

@Service
public class UserService {

    private final SysUserMapper userMapper;

    public UserService(SysUserMapper userMapper) {
        this.userMapper = userMapper;
    }

    /** 新增:自动回填主键 */
    public SysUser save(SysUser user) {
        userMapper.insert(user);
        return user;
    }

    /** 按主键删除(配置 @TableLogic 后为逻辑删除) */
    public void remove(Long id) {
        userMapper.deleteById(id);
    }

    /** 按主键更新:只更新非 null 字段 */
    public void modify(SysUser user) {
        userMapper.updateById(user);
    }

    /** 按主键查询 */
    public SysUser getById(Long id) {
        return userMapper.selectById(id);
    }

    /** 条件查询列表 */
    public List<SysUser> listByAge(Integer minAge) {
        return userMapper.selectList(
                new LambdaQueryWrapper<SysUser>()
                        .ge(SysUser::getAge, minAge)
                        .orderByDesc(SysUser::getId)
        );
    }
}

4.5 条件构造器 Wrapper

Wrapper 是 MyBatis-Plus 的核心,推荐使用 LambdaQueryWrapper / LambdaUpdateWrapper,避免硬编码字段名:

// 查询:用户名模糊匹配 + 年龄大于等于 18 + 按 id 倒序
LambdaQueryWrapper<SysUser> query = new LambdaQueryWrapper<SysUser>()
        .like(StringUtils.hasText(username), SysUser::getUsername, username)
        .ge(minAge != null, SysUser::getAge, minAge)
        .orderByDesc(SysUser::getId);
List<SysUser> users = userMapper.selectList(query);

// 更新:把年龄小于 18 的用户邮箱置空
LambdaUpdateWrapper<SysUser> update = new LambdaUpdateWrapper<SysUser>()
        .lt(SysUser::getAge, 18)
        .set(SysUser::getEmail, null);
userMapper.update(null, update);

// 删除:按条件删除
userMapper.delete(new LambdaQueryWrapper<SysUser>()
        .eq(SysUser::getUsername, "test"));

常用条件方法:

方法说明
eq / ne等于 / 不等于
gt / ge / lt / le大于 / 大于等于 / 小于 / 小于等于
like / likeLeft / likeRight模糊匹配
in / notInIN / NOT IN
isNull / isNotNull判空
between区间
orderByAsc / orderByDesc排序

4.6 分页插件

MyBatis-Plus 的分页需要注册插件:

@Configuration
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

使用分页:

public Page<SysUser> page(int pageNo, int pageSize) {
    Page<SysUser> page = new Page<>(pageNo, pageSize);
    return userMapper.selectPage(page,
            new LambdaQueryWrapper<SysUser>().orderByDesc(SysUser::getId));
}

4.7 自动填充与逻辑删除

自动填充需要实现 MetaObjectHandler:

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }
}

逻辑删除只需在实体字段上加 @TableLogic,并在配置中声明(3.5.x 默认已支持):

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted
      logic-delete-value: 1
      logic-not-delete-value: 0

配置后,deleteById 实际执行的是 UPDATE sys_user SET deleted = 1 WHERE id = ?,而所有查询会自动追加 deleted = 0 条件。

4.8 自定义 SQL 与 XML

MyBatis-Plus 并不排斥原生 SQL,复杂查询仍可写 XML:

@Mapper
public interface SysUserMapper extends BaseMapper<SysUser> {

    List<SysUser> selectByCondition(@Param("username") String username,
                                    @Param("minAge") Integer minAge);
}
<select id="selectByCondition" resultType="com.example.demo.entity.SysUser">
    SELECT * FROM sys_user
    <where>
        <if test="username != null and username != ''">
            AND username LIKE CONCAT('%', #{username}, '%')
        </if>
        <if test="minAge != null">
            AND age &gt;= #{minAge}
        </if>
    </where>
</select>

5. 两者对比与选型建议

维度MyBatisMyBatis-Plus
基础 CRUD需手写 SQL/XML继承 BaseMapper 即可
条件查询手写动态 SQLWrapper 链式调用
分页需引入 PageHelper 等内置分页插件
逻辑删除需手动处理@TableLogic 自动处理
自动填充需手动赋值MetaObjectHandler 自动填充
SQL 可控性完全可控完全可控(可写 XML)
学习成本较低略高(需理解 Wrapper)
适用场景复杂 SQL 多、SQL 需精细调优单表 CRUD 多、追求开发效率

选型建议:

  • 业务以单表增删改查为主、追求开发效率 → 优先 MyBatis-Plus。
  • 存在大量多表关联、复杂报表 SQL → 用 MyBatis-Plus 的 BaseMapper 处理简单场景,复杂 SQL 仍写 XML,两者可共存。
  • 团队对 SQL 有严格审计要求 → 原生 MyBatis 更直观,SQL 全部集中在 XML 中便于 review。

6. 总结

MyBatis 提供了灵活可控的 SQL 映射能力,是理解持久层原理的基础;MyBatis-Plus 在其之上补齐了通用 CRUD、条件构造器、分页、逻辑删除、自动填充等能力,大幅减少样板代码。

实际项目中,MyBatis-Plus + 自定义 XML 的组合最为常见:简单查询用 Wrapper 一行搞定,复杂 SQL 用 XML 精确控制,兼顾效率与可控性。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/qq_43565087/article/details/169141138

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--