MyBatis与MyBatis-Plus的区别

MyBatis 深度解析

核心组件
  1. SqlSessionFactory

    • 作用:创建 SqlSession 对象,是 MyBatis 的核心入口
    • 配置方式:
      • XML 配置(mybatis-config.xml)
      • Java 代码构建(较少使用)
  2. SqlSession

    • 作用:执行 SQL 命令、管理事务
    • 特点:非线程安全,建议每次使用时创建新实例
  3. Executor

    • 作用:执行 SQL 语句,处理缓存
    • 类型:
      • SimpleExecutor:每次执行都会创建新的 Statement
      • ReuseExecutor:重复使用 Statement
      • BatchExecutor:批量执行 SQL
  4. StatementHandler

    • 作用:处理 SQL 语句的预编译、参数设置、结果集映射
配置细节
  1. 全局配置文件

    <?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>
      <environments default="development">
        <environment id="development">
          <transactionManager type="JDBC"/>
          <dataSource type="POOLED">
            <property name="driver" value="${driver}"/>
            <property name="url" value="${url}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>
          </dataSource>
        </environment>
      </environments>
      <mappers>
        <mapper resource="mappers/UserMapper.xml"/>
      </mappers>
    </configuration>
    
  2. 映射文件结构

    <mapper namespace="com.example.mapper.UserMapper">
      <!-- 结果映射 -->
      <resultMap id="BaseResultMap" type="com.example.entity.User">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <result column="name" property="name" jdbcType="VARCHAR"/>
        <result column="age" property="age" jdbcType="INTEGER"/>
      </resultMap>
      
      <!-- 查询语句 -->
      <select id="selectById" resultMap="BaseResultMap">
        SELECT * FROM user WHERE id = #{id}
      </select>
      
      <!-- 插入语句 -->
      <insert id="insert" parameterType="com.example.entity.User">
        INSERT INTO user (name, age) VALUES (#{name}, #{age})
      </insert>
    </mapper>
    
高级特性
  1. 动态 SQL

    • 标签:<if><choose><when><otherwise><where><set><foreach>
    • 示例:
      <select id="findUsers" resultType="User">
        SELECT * FROM user
        <where>
          <if test="name != null">
            AND name = #{name}
          </if>
          <if test="age != null">
            AND age = #{age}
          </if>
        </where>
      </select>
      
  2. 缓存机制

    • 一级缓存:SqlSession 级别
    • 二级缓存:全局级别,跨 SqlSession 共享
    • 配置方式:
      <cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
      
  3. 插件机制

    • 可拦截的方法:Executor、ParameterHandler、ResultSetHandler、StatementHandler
    • 示例:
      @Intercepts({@Signature(
        type = Executor.class,
        method = "query",
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
      )})
      public class ExamplePlugin implements Interceptor {
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
          // 增强逻辑
          return invocation.proceed();
        }
      }
      

MyBatis-Plus 深度解析

核心组件
  1. BaseMapper

    • 内置方法:
      int insert(T entity);
      int deleteById(Serializable id);
      int updateById(@Param(Constants.ENTITY) T entity);
      T selectById(Serializable id);
      List<T> selectList(Wrapper<T> queryWrapper);
      
  2. IService

    • 内置方法:
      boolean save(T entity);
      boolean removeById(Serializable id);
      boolean updateById(T entity);
      T getById(Serializable id);
      List<T> list(Wrapper<T> queryWrapper);
      
  3. ServiceImpl

    • 实现 IService 接口,提供基础 CRUD 功能
    • 使用方式:
      @Service
      public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
        // 可扩展自定义方法
      }
      
增强特性
  1. 条件构造器

    • Lambda 表达式方式:
      List<User> userList = userService.list(
        new LambdaQueryWrapper<User>()
          .eq(User::getName, "张三")
          .ge(User::getAge, 18)
          .orderByDesc(User::getCreateTime)
      );
      
  2. 自动填充

    • 实现 MetaObjectHandler 接口:
      @Component
      public class MyMetaObjectHandler implements MetaObjectHandler {
        @Override
        public void insertFill(MetaObject metaObject) {
          this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        }
        
        @Override
        public void updateFill(MetaObject metaObject) {
          this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
        }
      }
      
  3. 逻辑删除

    • 实体类字段添加注解:
      @TableLogic
      private Integer deleted;
      
  4. 分页插件

    • 配置类:
      @Configuration
      public class MyBatisPlusConfig {
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor() {
          MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
          interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
          return interceptor;
        }
      }
      
  5. 代码生成器

    • 使用示例:
      FastAutoGenerator.create("jdbc:mysql://localhost:3306/test", "root", "password")
        .globalConfig(builder -> {
          builder.author("baomidou") // 设置作者
            .outputDir("D://mybatis-plus-code"); // 指定输出目录
        })
        .packageConfig(builder -> {
          builder.parent("com.example") // 设置父包名
            .moduleName("module") // 设置模块名
            .pathInfo(Collections.singletonMap(OutputFile.xml, "D://mybatis-plus-code/xml")); // 设置mapperXml生成路径
        })
        .strategyConfig(builder -> {
          builder.addInclude("user") // 设置需要生成的表名
            .addTablePrefix("t_", "c_"); // 设置过滤表前缀
        })
        .execute();
      

性能对比

场景MyBatis 执行时间MyBatis-Plus 执行时间原因分析
单表查询(无复杂条件)约 20ms约 25msMP 有额外的反射和代理开销
单表分页查询约 30ms约 35msMP 分页插件有一定开销
复杂多表联查约 50ms约 55msMP 优势不明显,需手写 SQL
批量插入 1000 条数据约 800ms约 600msMP 内置批量插入优化

最佳实践建议

  1. 项目选型

    • 新项目建议优先考虑 MyBatis-Plus,开发效率更高
    • 遗留项目已有大量 MyBatis 代码,可逐步引入 MyBatis-Plus
  2. 分层设计

    • Controller → Service → Mapper
    • Service 层使用 MyBatis-Plus 的 IService 和 ServiceImpl
    • 复杂查询在 Mapper 层自定义 SQL
  3. 复杂查询处理

    • 方式一:在 Mapper 接口中定义方法,XML 中编写 SQL
    • 方式二:使用 MyBatis-Plus 的 Wrapper 构造复杂条件
    • 方式三:结合 MyBatis-Plus 的 QueryWrapper 和自定义 SQL
  4. 分页处理

    • 单表分页:直接使用 MyBatis-Plus 分页插件
    • 复杂分页:自定义 SQL + 分页插件
  5. 事务管理

    • 使用 Spring 的 @Transactional 注解管理事务
    • 示例:
      @Service
      public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
        @Override
        @Transactional(rollbackFor = Exception.class)
        public boolean saveUserAndLog(User user) {
          // 保存用户
          boolean result = this.save(user);
          // 记录日志
          logService.saveLog("用户注册:" + user.getName());
          return result;
        }
      }
      

常见问题与解决方案

  1. MyBatis 问题

    • 问题:SQL 注入风险
    • 解决方案:使用 #{} 占位符,避免使用 ${}
  2. MyBatis-Plus 问题

    • 问题:复杂查询性能不如纯手写 SQL
    • 解决方案:复杂查询部分使用自定义 SQL
  3. 通用问题

    • 问题:字段映射不一致
    • 解决方案
      • 使用 @TableField 注解
      • 配置全局下划线转驼峰
  4. 分页问题

    • 问题:分页插件不生效
    • 解决方案
      • 检查分页插件是否正确配置
      • 确保调用的是 Page 相关方法
  5. 缓存问题

    • 问题:二级缓存导致数据不一致
    • 解决方案
      • 敏感数据禁用二级缓存
      • 更新数据时及时清除缓存

通过以上对比可以看出,MyBatis-Plus 在保持 MyBatis 核心功能的基础上,显著提升了开发效率,尤其适合以 CRUD 操作为主的项目。但在复杂 SQL 场景下,仍需要结合 MyBatis 的原生能力。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值