公司动态

Spring Boot与MyBatis-Plus整合开发实战指南

📅 2026/7/21 7:21:20
Spring Boot与MyBatis-Plus整合开发实战指南
1. 为什么选择Spring Boot与MyBatis-Plus组合在Java企业级开发领域ORM框架的选择直接影响着开发效率和系统性能。MyBatis作为老牌持久层框架虽然灵活但需要大量模板代码Hibernate虽然功能强大但学习曲线陡峭且对复杂SQL支持不足。MyBatis-Plus在MyBatis基础上做了增强而Spring Boot提供了快速启动的能力两者的结合堪称Java后端开发的黄金搭档。我经历过从原生JDBC到各种ORM框架的演进过程最终在团队项目中全面采用Spring Boot MyBatis-Plus方案。这套组合最吸引人的是MyBatis-Plus的BaseMapper提供了单表CRUD的零实现配合Spring Boot的自动配置开发常规业务接口时甚至不需要写任何SQL语句。比如用户管理模块的基础增删改查传统MyBatis需要编写5个接口方法5个XML映射而用MyBatis-Plus只需要继承BaseMapper就自动获得全部功能。2. 环境准备与项目初始化2.1 开发环境要求推荐使用以下环境组合这也是我们团队经过多个项目验证的稳定配置JDK 17Spring Boot 3.x的最低要求Maven 3.6或Gradle 7.xIntelliJ IDEA 2023对Spring Boot支持最完善的IDEMySQL 8.0或PostgreSQL 14生产环境推荐注意如果公司内部还在使用JDK8需要选择Spring Boot 2.7.x MyBatis-Plus 3.5.3.x的组合。新项目强烈建议直接上Spring Boot 3.x系列。2.2 项目初始化实操通过start.spring.io创建项目时建议勾选以下依赖Spring Web如果要做Web应用Lombok减少样板代码MySQL Driver或其他数据库驱动对于已有项目添加MyBatis-Plus依赖时要注意版本匹配!-- Spring Boot 3.x 选择此starter -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-spring-boot3-starter/artifactId version3.5.5/version /dependency !-- 如果使用Spring Boot 2.x -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.2/version /dependency3. 核心配置详解3.1 数据源配置在application.yml中配置数据源时建议增加连接池配置spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/demo?useSSLfalseserverTimezoneAsia/Shanghai username: root password: 123456 hikari: maximum-pool-size: 20 minimum-idle: 5 connection-timeout: 30000 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开启SQL日志 map-underscore-to-camel-case: true # 自动转驼峰3.2 Mapper扫描与实体类主启动类需要添加MapperScan注解SpringBootApplication MapperScan(com.example.demo.mapper) public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }实体类建议使用Lombok简化代码Data TableName(sys_user) // 指定表名 public class User { TableId(type IdType.AUTO) // 主键自增 private Long id; private String username; private String password; TableField(nick_name) // 字段映射 private String nickname; }4. 基础CRUD实战4.1 Mapper接口定义继承BaseMapper即可获得18个常用方法public interface UserMapper extends BaseMapperUser { // 自定义方法 ListUser selectByName(Param(name) String name); }4.2 服务层实现Service层可以继承ServiceImpl获得批量操作方法Service public class UserServiceImpl extends ServiceImplUserMapper, User implements UserService { public ListUser getAdmins() { LambdaQueryWrapperUser wrapper new LambdaQueryWrapper(); wrapper.eq(User::getRole, admin); return baseMapper.selectList(wrapper); } }4.3 控制器示例RESTful接口的典型实现RestController RequestMapping(/users) public class UserController { Autowired private UserService userService; GetMapping(/{id}) public ResultUser getById(PathVariable Long id) { return Result.success(userService.getById(id)); } PostMapping public ResultBoolean save(RequestBody User user) { return Result.success(userService.save(user)); } }5. 高级特性应用5.1 条件构造器实战QueryWrapper和LambdaQueryWrapper的对比使用// 传统QueryWrapper QueryWrapperUser wrapper new QueryWrapper(); wrapper.select(id, username) .like(username, 张) .between(age, 20, 30) .orderByDesc(create_time); // Lambda写法推荐 LambdaQueryWrapperUser lambdaWrapper new LambdaQueryWrapper(); lambdaWrapper.select(User::getId, User::getUsername) .like(User::getUsername, 张) .between(User::getAge, 20, 30) .orderByDesc(User::getCreateTime);5.2 分页查询实现配置分页插件后即可使用Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return interceptor; } } // 使用示例 PageUser page new Page(1, 10); PageUser result userMapper.selectPage(page, null);5.3 自动填充功能实现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()); } }6. 生产环境最佳实践6.1 多数据源配置使用dynamic-datasource-spring-boot-starterspring: datasource: dynamic: primary: master datasource: master: url: jdbc:mysql://localhost:3306/master username: root password: 123456 slave: url: jdbc:mysql://localhost:3306/slave username: root password: 1234566.2 性能优化建议批量操作使用executeBatchuserMapper.insertBatchSomeColumn(list);复杂查询开启二级缓存CacheNamespace public interface UserMapper extends BaseMapperUser { }避免N1查询问题Select(select * from user where id in #{ids}) ListUser selectBatchIds(Param(ids) ListLong ids);7. 常见问题排查7.1 典型异常处理注入失败检查MapperScan路径是否正确表名映射错误确认TableName和数据库表名一致字段找不到检查TableField或是否开启map-underscore-to-camel-case7.2 日志分析技巧开启mybatis-plus.configuration.log-impl后可以观察到 Preparing: SELECT id,username FROM user WHERE username LIKE ? AND age BETWEEN ? AND ? ORDER BY create_time DESC Parameters: %张%(String), 20(Integer), 30(Integer)通过分析日志可以快速定位SQL拼接问题。8. 插件扩展开发8.1 自定义拦截器实现分页逻辑的拦截器示例Intercepts(Signature(type StatementHandler.class, method prepare, args {Connection.class, Integer.class})) public class MyPaginationInterceptor implements Interceptor { Override public Object intercept(Invocation invocation) throws Throwable { // 分页逻辑实现 return invocation.proceed(); } }8.2 自定义类型处理器处理JSON字段的TypeHandlerpublic class JsonTypeHandlerT extends BaseTypeHandlerT { private final ClassT type; public JsonTypeHandler(ClassT type) { this.type type; } Override public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, JSON.toJSONString(parameter)); } Override public T getNullableResult(ResultSet rs, String columnName) throws SQLException { return JSON.parseObject(rs.getString(columnName), type); } }在实际项目开发中Spring Boot和MyBatis-Plus的组合能显著提升开发效率。特别是在快速迭代的业务场景下这套技术栈可以让开发者更专注于业务逻辑而非底层实现。根据我们团队的经验采用这套方案后基础CRUD接口的开发时间能缩短60%以上。