1. 理解MyBatis-Plus中的BaseMapper1.1 什么是BaseMapperBaseMapper是MyBatis-Plus框架提供的一个核心接口它封装了最基础的CRUDCreate, Read, Update, Delete操作方法。当我们在DAO层接口中声明extends BaseMapperUserEntity时实际上是在继承这个预置的通用接口。这个设计采用了泛型编程的思想UserEntity表示这个Mapper专门操作UserEntity类型的数据。MyBatis-Plus会在运行时自动为这个接口生成实现类无需开发者手动编写SQL语句。1.2 BaseMapper的核心方法BaseMapper接口中预定义了约20个常用方法主要包括// 插入操作 int insert(T entity); // 删除操作 int deleteById(Serializable id); int deleteByMap(Param(cm) MapString, Object columnMap); int delete(Param(ew) WrapperT wrapper); // 更新操作 int updateById(Param(et) T entity); int update(Param(et) T entity, Param(ew) WrapperT updateWrapper); // 查询操作 T selectById(Serializable id); ListT selectBatchIds(Param(coll) Collection? extends Serializable idList); ListT selectByMap(Param(cm) MapString, Object columnMap); T selectOne(Param(ew) WrapperT queryWrapper); // 计数操作 Long selectCount(Param(ew) WrapperT queryWrapper);这些方法已经覆盖了90%以上的单表操作场景开发者无需再编写重复的SQL语句。2. 泛型参数的作用与实现原理2.1 泛型参数的意义UserEntity这个泛型参数起到了三个关键作用类型安全所有方法的参数和返回值都会自动适配UserEntity类型表映射框架会自动将UserEntity类与数据库表进行关联SQL生成根据实体类属性自动生成对应的SQL语句2.2 MyBatis-Plus的实现机制当Spring容器启动时MyBatis-Plus会通过以下步骤处理这个接口扫描所有继承BaseMapper的接口使用动态代理技术生成实现类解析泛型参数获取实体类类型根据实体类注解(TableName等)确定对应的数据库表为每个方法生成对应的SQL实现整个过程对开发者完全透明这也是MyBatis-Plus约定优于配置理念的体现。3. 实际开发中的应用场景3.1 基础CRUD操作继承BaseMapper后我们可以直接使用预定义的方法// 插入用户 UserEntity user new UserEntity(); user.setName(张三); user.setAge(25); userMapper.insert(user); // 查询用户 UserEntity result userMapper.selectById(1L); // 更新用户 user.setAge(26); userMapper.updateById(user); // 删除用户 userMapper.deleteById(1L);3.2 配合Wrapper使用BaseMapper的强大之处在于可以与Wrapper条件构造器配合使用// 条件查询 QueryWrapperUserEntity wrapper new QueryWrapper(); wrapper.like(name, 张) .between(age, 20, 30) .orderByDesc(create_time); ListUserEntity users userMapper.selectList(wrapper); // 条件更新 UpdateWrapperUserEntity updateWrapper new UpdateWrapper(); updateWrapper.set(age, 30) .eq(name, 张三); userMapper.update(null, updateWrapper);4. 扩展与自定义4.1 自定义SQL方法虽然BaseMapper提供了丰富的方法但有时我们仍需要自定义SQLpublic interface UserMapper extends BaseMapperUserEntity { Select(SELECT * FROM user WHERE age #{age}) ListUserEntity selectByAgeGreaterThan(Param(age) Integer age); }MyBatis-Plus会智能地合并继承的方法和自定义方法。4.2 多表联查解决方案对于复杂的多表查询建议采用以下方案使用Select注解编写自定义SQL创建VO类接收结果在XML中定义resultMap处理复杂映射Select(SELECT u.*, d.dept_name FROM user u LEFT JOIN department d ON u.dept_id d.id) ListUserVO selectUserWithDept();5. 性能优化与最佳实践5.1 批量操作优化BaseMapper提供了批量操作方法但需要注意// 批量插入实际是循环单条插入性能一般 ListUserEntity userList ...; userMapper.insertBatchSomeColumn(userList); // 需要配置logic-not-delete-field // 真正高效的批量插入应该使用SQLSession SqlSession sqlSession sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH); UserMapper batchMapper sqlSession.getMapper(UserMapper.class); for(UserEntity user : userList) { batchMapper.insert(user); } sqlSession.commit();5.2 字段注解的正确使用合理使用注解可以优化SQL生成TableName(sys_user) // 指定表名 public class UserEntity { TableId(type IdType.AUTO) // 主键策略 private Long id; TableField(user_name) // 字段映射 private String name; TableField(exist false) // 非表字段 private String tempValue; }6. 常见问题排查6.1 映射失败问题当出现Table xxx doesnt exist错误时检查实体类是否有TableName注解数据库表名是否正确是否配置了全局表名前缀(global-config.db-config.table-prefix)6.2 主键冲突问题主键策略配置不当会导致插入失败// 正确的主键策略配置 TableId(type IdType.AUTO) // 数据库自增 TableId(type IdType.ASSIGN_ID) // 雪花算法(默认) TableId(type IdType.INPUT) // 手动输入6.3 逻辑删除配置实现逻辑删除需要正确配置mybatis-plus: global-config: db-config: logic-delete-field: deleted # 逻辑删除字段名 logic-not-delete-value: 0 # 未删除值 logic-delete-value: 1 # 删除值7. 源码解析与实现原理7.1 动态代理机制MyBatis-Plus通过MapperProxy实现接口方法的动态代理为每个Mapper接口创建代理对象方法调用时根据方法名和参数选择执行策略对于BaseMapper方法使用预定义的SQL模板对于自定义方法走原生MyBatis流程7.2 SQL自动生成核心类SqlMethod定义了各种操作对应的SQL模板public enum SqlMethod { INSERT(insert, 插入一条数据, INSERT INTO %s %s VALUES %s), DELETE_BY_ID(deleteById, 根据ID删除一条数据, DELETE FROM %s WHERE %s#{%s}), SELECT_BY_ID(selectById, 根据ID查询一条数据, SELECT %s FROM %s WHERE %s#{%s}), // 其他方法... }框架会根据实体类信息填充这些模板中的占位符。8. 高级特性与扩展点8.1 自定义注入方法通过ISqlInjector接口可以扩展BaseMapperpublic class MySqlInjector extends DefaultSqlInjector { Override public ListAbstractMethod getMethodList(Class? mapperClass) { ListAbstractMethod methodList super.getMethodList(mapperClass); methodList.add(new DeleteAll()); // 添加自定义方法 return methodList; } }8.2 租户处理器实现多租户数据隔离public class MyTenantHandler implements TenantLineHandler { Override public Expression getTenantId() { return new StringValue(TenantContext.getCurrentTenant()); } Override public String getTenantIdColumn() { return tenant_id; } Override public boolean ignoreTable(String tableName) { return !user.equals(tableName); // 指定哪些表需要过滤 } }9. 版本差异与升级指南9.1 3.x与2.x的主要区别移除了AR(ActiveRecord)模式条件构造器API重构分页插件实现方式变化主键策略调整9.2 升级注意事项检查所有Wrapper的使用方式重新评估分页实现测试批量操作方法验证自动填充功能10. 实战经验分享在实际项目中我们总结了以下经验复杂查询处理对于超过3表关联的查询建议使用原生MyBatis实现性能监控添加InterceptorIgnore注解排除不需要监控的方法InterceptorIgnore(illegalSql true, blockAttack true) ListUserEntity selectAll();动态表名实现IDynamicTableName接口处理分表场景public class UserEntity implements IDynamicTableName { private String year; // 分表后缀 Override public String getDynamicTableName() { return user_ year; } }字段加密通过FieldEncrypt注解实现自动加解密FieldEncrypt private String password;多数据源结合DS注解实现动态数据源切换DS(slave) // 指定从库 UserEntity selectById(Long id);