当前位置: 首页 > news >正文

MyBatis 和 MyBatis-Plus对比

MyBatis 和 MyBatis-Plus 是 Java 生态中常用的持久层框架,其中 MyBatis-Plus 是在 MyBatis 基础上的增强工具(“只做增强,不做改变”)。下面从语法详解优劣对比两部分展开说明。

一、MyBatis 语法详解

MyBatis 的核心是 “SQL 映射”,通过 XML 或注解将 Java 方法与 SQL 语句绑定,需手动定义 SQL 逻辑。其语法围绕 “配置文件 + Mapper 接口 + SQL 映射(XML / 注解)” 展开。

1. 核心配置文件(mybatis-config.xml)

用于全局配置 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><!-- 1. 环境配置(数据源) --><environments default="dev"><environment id="dev"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/test"/><property name="username" value="root"/><property name="password" value="123456"/></dataSource></environment></environments><!-- 2. 别名配置(简化类名引用) --><typeAliases><package name="com.example.entity"/> <!-- 扫描包,别名默认为类名(首字母小写) --></typeAliases><!-- 3. 映射器(关联Mapper接口与SQL映射文件) --><mappers><package name="com.example.mapper"/> <!-- 扫描Mapper接口所在包 --></mappers>
</configuration>
2. Mapper 接口

定义数据操作方法,需与 SQL 映射(XML / 注解)绑定,示例如下:

public interface UserMapper {// 根据ID查询用户User selectById(Long id);// 新增用户int insert(User user);// 批量删除用户int deleteBatch(@Param("ids") List<Long> ids);
}
3. SQL 映射(XML 方式,核心)

通过 XML 标签定义 SQL,支持动态 SQL(MyBatis 一大特色),示例如下(UserMapper.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">
<!-- namespace绑定Mapper接口 -->
<mapper namespace="com.example.mapper.UserMapper"><!-- 1. 基础查询:根据ID查用户 --><select id="selectById" resultType="User"> <!-- id对应接口方法名,resultType对应返回类型(别名) -->SELECT id, username, age, create_time FROM user WHERE id = #{id} <!-- #{id}是参数占位符(预编译,防SQL注入) --></select><!-- 2. 新增用户 --><insert id="insert" parameterType="User"> <!-- parameterType是参数类型 -->INSERT INTO user(username, age, create_time) VALUES(#{username}, #{age}, #{createTime}) <!-- #{属性名}对应实体类字段(需与数据库字段映射) --></insert><!-- 3. 动态SQL:批量删除(if+foreach) --><delete id="deleteBatch">DELETE FROM user<where> <!-- where标签自动处理多余的AND/OR --><if test="ids != null and ids.size() > 0"> <!-- if标签:条件判断(test里是OGNL表达式) -->id IN <foreach collection="ids" item="id" open="(" close=")" separator=","> <!-- foreach遍历集合 -->#{id}</foreach></if></where></delete><!-- 4. 动态SQL:复杂查询(choose/when/otherwise) --><select id="selectByCondition" resultType="User">SELECT * FROM user<where><choose> <!-- choose类似Java的switch:只执行第一个满足条件的when --><when test="username != null">username LIKE CONCAT('%', #{username}, '%')</when><when test="age != null">age = #{age}</when><otherwise>1=1</otherwise> <!-- 默认条件(避免where后无内容) --></choose></where></select>
</mapper>
4. SQL 映射(注解方式,适合简单 SQL)

直接在 Mapper 接口方法上用注解定义 SQL,无需 XML,示例如下:

public interface UserMapper {@Select("SELECT id, username FROM user WHERE id = #{id}")User selectById(Long id);@Insert("INSERT INTO user(username, age) VALUES(#{username}, #{age})")int insert(User user);
}

二、MyBatis-Plus 语法详解

MyBatis-Plus(简称 “MP”)基于 MyBatis 开发,核心是 “增强 CRUD”—— 通过继承接口、条件构造器等简化开发,无需手动写基本 SQL,同时兼容 MyBatis 语法(可混合使用)。

1. 核心依赖与配置

需引入 MyBatis-Plus 依赖(需排除 MyBatis 重复依赖),配置与 MyBatis 类似,仅需新增 MP 专属插件(如分页插件),示例如下(Spring Boot 环境):

@Configuration
@MapperScan("com.example.mapper") // 扫描Mapper接口
public class MyBatisPlusConfig {// 分页插件(MP提供,开箱即用)@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 适配MySQLreturn interceptor;}
}
2. 核心接口:BaseMapper<T>(简化 CRUD)

MP 提供 BaseMapper<T> 接口,内置常用 CRUD 方法,自定义 Mapper 只需继承它即可,无需手动写 SQL。

示例

// 实体类(需与数据库表映射,用MP注解)
@Data
@TableName("user") // 指定数据库表名(默认类名小写)
public class User {@TableId(type = IdType.AUTO) // 主键策略(自增)private Long id;private String username;private Integer age;@TableField("create_time") // 映射数据库字段(若属性名与字段名一致可省略)private LocalDateTime createTime;
}// Mapper接口:继承BaseMapper<T>,无需写方法
public interface UserMapper extends BaseMapper<User> { // 已继承BaseMapper的20+个方法:insert、selectById、updateById、deleteById、selectList等
}

直接调用继承的方法(Service 层示例):

@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public void testCRUD() {// 1. 新增User user = new User();user.setUsername("mp-test");user.setAge(20);userMapper.insert(user); // 直接调用BaseMapper的insert方法// 2. 根据ID查询User user = userMapper.selectById(1L);// 3. 更新(根据ID)user.setAge(21);userMapper.updateById(user); // 仅更新非null字段// 4. 删除(根据ID)userMapper.deleteById(1L);// 5. 查询所有List<User> users = userMapper.selectList(null); // 参数为条件构造器,null表示无条件}
}
3. 条件构造器:QueryWrapper/UpdateWrapper(动态 SQL 简化)

MP 提供 QueryWrapper(查询条件)和 UpdateWrapper(更新条件),通过链式方法动态构建条件,无需写 XML 动态 SQL 标签。

示例 1:QueryWrapper(查询条件)

public List<User> selectByCondition() {// 构建查询条件:查询年龄>20、用户名含"张"、且创建时间在2023年后的用户QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.gt("age", 20) // gt:大于(字段名用数据库列名,或实体类属性名).like("username", "张") // like:模糊查询(默认%值%).ge("create_time", LocalDateTime.of(2023, 1, 1, 0, 0, 0)) // ge:大于等于.orderByDesc("create_time"); // 排序:按创建时间降序// 调用selectList,传入条件构造器return userMapper.selectList(queryWrapper);
}

示例 2:UpdateWrapper(更新条件)

public void updateByCondition() {// 构建更新条件:将年龄<18的用户的username改为"未成年"UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();updateWrapper.lt("age", 18) // lt:小于(条件).set("username", "未成年"); // set:更新的字段及值// 调用update,传入null(无需实体类)和条件构造器userMapper.update(null, updateWrapper);
}
4. 分页查询(开箱即用)

MP 分页插件配置后,直接用 IPage 接口即可实现分页,无需手动写 LIMIT 语句:

public IPage<User> selectPage(int pageNum, int pageSize) {// 1. 创建分页对象(pageNum:页码,pageSize:每页条数)IPage<User> page = new Page<>(pageNum, pageSize);// 2. 调用selectPage方法(BaseMapper提供),传入分页对象和条件构造器(null表示查所有)return userMapper.selectPage(page, null); // 返回结果包含:总条数(total)、总页数(pages)、当前页数据(records)等
}
5. 其他增强功能(语法涉及注解 / 配置)
  • 逻辑删除:通过 @TableLogic 注解标记逻辑删除字段(如 deleted),删除时自动改为 “更新 deleted=1”,查询时自动过滤 deleted=0

    @TableLogic // 标记逻辑删除字段
    private Integer deleted;
    
  • 自动填充:通过 @TableField(fill = ...) 标记需自动填充的字段(如 createTime),配合 MetaObjectHandler 实现新增 / 更新时自动赋值:

    @TableField(fill = FieldFill.INSERT) // 新增时自动填充
    private LocalDateTime createTime;// 自定义填充处理器
    @Component
    public class MyMetaObjectHandler implements MetaObjectHandler {@Overridepublic void insertFill(MetaObject metaObject) {this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());}
    }
    
  • 代码生成器:通过 AutoGenerator 自动生成 Entity、Mapper、Service、Controller 等代码,减少重复工作:

    public class CodeGenerator {public static void main(String[] args) {AutoGenerator generator = new AutoGenerator();// 配置数据源、包名、策略等(略)generator.execute(); // 执行生成}
    }
    

三、MyBatis 与 MyBatis-Plus 的优劣对比

两者核心差异在于 “开发效率” 与 “灵活性” 的权衡,具体对比如下:

1. MyBatis 的优劣

优势

  • 灵活性极高:开发者可完全控制 SQL 语句,支持复杂查询(如多表联查、子查询、自定义函数等),适合业务逻辑复杂的场景(如金融、电商核心业务)。
  • SQL 优化可控:可直接通过调整 SQL 语句优化性能(如索引利用、查询字段精简),对底层 SQL 透明。
  • 学习成本低:核心逻辑是 “SQL 映射”,只需掌握 XML / 注解与 SQL 的绑定,概念简单清晰。
  • 无额外依赖:轻量框架,仅需 MyBatis 核心包,无多余封装,适合对依赖体积敏感的项目。

劣势

  • 重复代码多:基本 CRUD(增删改查)需手动写 SQL(即使逻辑简单),Mapper 接口、XML 映射文件需一一对应,开发效率低。
  • 动态 SQL 繁琐:复杂动态 SQL 需写大量 XML 标签(如 if/foreach/where),易出错且维护困难(如标签嵌套、语法错误)。
  • 功能需手动扩展:分页、逻辑删除等功能需自己实现(如自定义分页插件、手动加 deleted 判断),无开箱即用的解决方案。
2. MyBatis-Plus 的优劣

优势

  • 开发效率极高:继承 BaseMapper 即可实现 80% 以上的基础 CRUD,无需写 SQL;条件构造器简化动态 SQL,无需 XML 标签。
  • 功能丰富且开箱即用:内置分页、逻辑删除、自动填充、代码生成器等功能,无需手动开发,适合快速迭代的项目(如后台管理系统、中小业务)。
  • 兼容 MyBatis:可无缝混合使用 MyBatis 语法(如复杂查询仍用 XML 写 SQL),既保留灵活性又提升效率。
  • 降低新手门槛:无需熟练掌握 XML 动态 SQL,通过条件构造器的链式方法即可完成大部分查询,新手易上手。

劣势

  • 复杂查询灵活性不足:虽然支持自定义 SQL,但过度依赖条件构造器可能导致复杂查询(如多表联查 + 动态条件)写法繁琐,不如直接写 SQL 直观。
  • 框架依赖增加:需引入 MyBatis-Plus 依赖,且部分功能(如代码生成器)需额外配置,对 “轻量” 有要求的项目可能不适用。
  • 底层 SQL 透明性低:条件构造器生成的 SQL 需通过日志查看,若对 MP API 不熟悉,可能出现 “预期外 SQL”(如条件拼接错误),排查问题成本高。
  • 团队学习成本:需掌握 MP 专属 API(如条件构造器方法、注解),若团队成员不熟悉,可能出现用法不统一的问题。

四、总结:如何选择?

  • 选 MyBatis:若项目业务复杂(多复杂查询)、对 SQL 可控性要求高(需频繁优化),或团队更习惯直接写 SQL。
  • 选 MyBatis-Plus:若项目以基础 CRUD 为主(如后台管理系统)、追求快速开发,或需减少重复代码(如自动填充、分页),可大幅提升效率。

实际开发中,两者常结合使用:基础 CRUD 用 MP 简化开发,复杂查询用 MyBatis 的 XML 写原生 SQL,兼顾效率与灵活性。

http://www.dtcms.com/a/348793.html

相关文章:

  • 【GEE+Python 实战】用 Sentinel-2 监测 2024 年研究区 NDVI 变化(附完整源码与避坑指南)
  • 深入解析十大经典排序算法原理与实现
  • 理想汽车智驾方案介绍 2|MindVLA 方案详解
  • Java 编译器的世界:前端、JIT 与 AOT 的秘密:详解 Java 的编译过程与编译器生态
  • 秦始皇在位时的重要贡献
  • 室联人形机器人:家政服务任务结构化、技术要点、深入应用FPGA的控制系统框架设计(整合版A)
  • Redis 启动的三种方式:从基础到实战配置指南
  • WSL-linux部署IndexTTS 记录(含本地 CUDA/cuDNN 编译依赖说明)
  • 深度剖析Spring AI源码(二):Model抽象层 - “驯服”天下AI的“紧箍咒”
  • 《Linux 网络编程二:UDP 与 TCP 的差异、应用及问题应对》
  • Grafana k6 性能测试
  • golang5字符串
  • Linux驱动之DMA(三)
  • 强光干扰下漏检率↓78%!陌讯动态决策算法在智慧交通违停检测的实战优化
  • 自动化运维之k8s——Kubernetes集群部署、pod、service微服务、kubernetes网络通信
  • SSRF的学习笔记
  • MATLAB 入门:从变量定义到基础绘图的完整上手指南
  • 学习Java25天
  • 杭电oj第2061题:Treasure the new start, freshmen!
  • 今天学习计算机网格技术的TCP,UDP以及OSPF
  • 南科大C++ 第四章(数组,结构体,联合体,枚举)
  • odoo 工作台
  • Microsoft .NET Packages AIO:全面的.NET开发框架
  • 强光干扰下检出率↑93%!陌讯多模态融合算法在充电桩车位占用检测的实战解析
  • DDR3入门系列(一)——初识DDR3
  • FastAPI中定时任务的使用详解
  • Kernel Pwn 入门(五) 条件竞争 userfaultfd利用
  • PMP项目管理知识点-②项⽬环境
  • LeetCode 第464场周赛 第三天
  • 抽奖池项目测试