Spring Boot 3.0与MyBatis Plus集成开发指南 1. 为什么选择Spring Boot 3.0与MyBatis Plus组合在Java企业级应用开发领域Spring Boot 3.0和MyBatis Plus的组合已经成为2023年技术选型的热门选择。Spring Boot 3.0作为Spring框架的最新里程碑版本带来了对Java 17的强制要求、GraalVM原生镜像支持等重大改进。而MyBatis Plus作为MyBatis的增强工具在保留MyBatis灵活性的同时提供了强大的CRUD操作简化、代码生成器和丰富的插件体系。这个组合特别适合需要快速开发但又不想完全放弃SQL控制权的项目场景。相比JPA的完全面向对象MyBatis Plus允许开发者保留对SQL的精确控制同时通过其增强功能大幅减少样板代码。我在多个生产项目中采用这个组合后DAO层代码量平均减少了60%而复杂查询的性能调优空间仍然完全保留。2. 环境准备与项目初始化2.1 基础环境要求在开始集成前需要确保开发环境满足以下要求JDK 17或更高版本Spring Boot 3.0的强制要求Maven 3.5或Gradle 7.x本文以Maven为例IDE支持推荐IntelliJ IDEA 2022.3数据库准备MySQL 8.0、PostgreSQL 14等主流关系型数据库注意Spring Boot 3.0不再支持Java 8和Java 11这是与2.x版本最大的区别之一。如果团队还在使用旧版Java需要考虑升级成本。2.2 创建Spring Boot 3.0项目使用Spring Initializr创建项目时需要特别注意依赖选择访问 https://start.spring.io选择Project: MavenLanguage: JavaSpring Boot: 3.0.x添加依赖Spring WebMyBatis Framework对应数据库驱动如MySQL Driver或者使用命令行快速创建curl https://start.spring.io/starter.zip -d dependenciesweb,mybatis,mysql \ -d javaVersion17 -d typemaven-project -d bootVersion3.0.6 -o mybatis-plus-demo.zip3. MyBatis Plus的核心集成步骤3.1 添加MyBatis Plus依赖在pom.xml中添加以下依赖注意版本兼容性dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency为什么选择这个版本因为它专门为Spring Boot 3.0做了适配修复了多个与Java 17兼容性问题支持最新的MyBatis 3.5.11核心3.2 数据库配置application.yml中配置数据源以MySQL为例spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/demo?useSSLfalseserverTimezoneUTC username: root password: yourpassword mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开启SQL日志 global-config: db-config: id-type: auto # 主键策略3.3 实体类与Mapper示例创建用户实体类Data TableName(sys_user) // 指定表名 public class User { TableId(type IdType.AUTO) // 主键自增 private Long id; private String username; private String email; TableField(pwd) // 字段映射 private String password; TableField(fill FieldFill.INSERT) // 自动填充 private LocalDateTime createTime; }创建Mapper接口public interface UserMapper extends BaseMapperUser { // 自定义复杂查询 Select(SELECT * FROM sys_user WHERE email LIKE %#{domain}) ListUser selectByEmailDomain(String domain); }技巧BaseMapper已经提供了insert、delete、update、select等17个常用方法无需手动编写。4. 高级功能与最佳实践4.1 分页插件配置MyBatis Plus的分页功能需要额外配置Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); // 分页插件 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 乐观锁插件 interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; } }使用示例PageUser page new Page(1, 10); // 第1页每页10条 PageUser result userMapper.selectPage(page, null);4.2 代码生成器实战MyBatis Plus的代码生成器可以大幅提升开发效率public class CodeGenerator { public static void main(String[] args) { AutoGenerator generator new AutoGenerator(); // 全局配置 GlobalConfig config new GlobalConfig(); config.setOutputDir(System.getProperty(user.dir) /src/main/java); config.setAuthor(YourName); config.setOpen(false); generator.setGlobalConfig(config); // 数据源配置 DataSourceConfig dataSource new DataSourceConfig(); dataSource.setUrl(jdbc:mysql://localhost:3306/demo); dataSource.setDriverName(com.mysql.cj.jdbc.Driver); dataSource.setUsername(root); dataSource.setPassword(yourpassword); generator.setDataSource(dataSource); // 包配置 PackageConfig packageConfig new PackageConfig(); packageConfig.setParent(com.example.demo); packageConfig.setEntity(entity); packageConfig.setMapper(mapper); generator.setPackageInfo(packageConfig); generator.execute(); } }4.3 多数据源配置在实际项目中经常需要连接多个数据库。Spring Boot 3.0下配置多数据源Configuration MapperScan(basePackages com.example.mapper.primary, sqlSessionTemplateRef primarySqlSessionTemplate) public class PrimaryDataSourceConfig { Bean ConfigurationProperties(prefix spring.datasource.primary) public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } Bean public SqlSessionFactory primarySqlSessionFactory(Qualifier(primaryDataSource) DataSource dataSource) throws Exception { MybatisSqlSessionFactoryBean factoryBean new MybatisSqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources(classpath:mapper/primary/*.xml)); return factoryBean.getObject(); } Bean public SqlSessionTemplate primarySqlSessionTemplate( Qualifier(primarySqlSessionFactory) SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); } }5. 性能优化与问题排查5.1 SQL性能监控集成p6spy进行SQL监控dependency groupIdp6spy/groupId artifactIdp6spy/artifactId version3.9.1/version /dependencyapplication.yml配置spring: datasource: driver-class-name: com.p6spy.engine.spy.P6SpyDriver url: jdbc:p6spy:mysql://localhost:3306/demo创建spy.propertiesmodule.logcom.p6spy.engine.logging.P6LogFactory appendercom.p6spy.engine.spy.appender.Slf4JLogger logMessageFormatcom.p6spy.engine.spy.appender.CustomLineFormat customLogMessageFormat%(executionTime)ms | %(category) | connection %(connectionId) | %(sqlSingleLine)5.2 常见问题解决方案问题1插入后无法获取自增ID解决方案TableId(type IdType.AUTO) private Long id;确保数据库字段是AUTO_INCREMENT并且Mapper使用insert方法而非insertSelective问题2字段名与数据库关键字冲突解决方案TableField(order) private Integer order;问题3LocalDateTime序列化问题解决方案Bean public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() { return builder - builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ISO_DATE_TIME)); }6. 实际项目中的经验分享在电商系统开发中我们遇到了商品分页查询性能问题。通过MyBatis Plus的QueryWrapper和自定义SQL结合最终实现了高性能分页public PageProduct searchProducts(ProductQuery query, Pageable pageable) { PageProduct page new Page(pageable.getPageNumber(), pageable.getPageSize()); QueryWrapperProduct wrapper new QueryWrapper(); if (StringUtils.hasText(query.getKeyword())) { wrapper.and(w - w.like(name, query.getKeyword()) .or() .like(description, query.getKeyword())); } if (query.getCategoryId() ! null) { wrapper.eq(category_id, query.getCategoryId()); } // 使用自定义SQL处理复杂条件 String sql wrapper.getCustomSqlSegment(); return productMapper.selectPageWithCustomSql(page, sql); }另一个实用技巧是使用MyBatis Plus的自动填充功能处理审计字段Component public class MyMetaObjectHandler implements MetaObjectHandler { Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, createTime, LocalDateTime.class, LocalDateTime.now()); this.strictInsertFill(metaObject, createBy, String.class, getCurrentUsername()); } Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, updateTime, LocalDateTime.class, LocalDateTime.now()); this.strictUpdateFill(metaObject, updateBy, String.class, getCurrentUsername()); } }对于需要处理大量数据的场景可以使用MyBatis Plus的流式查询Select(SELECT * FROM large_table) Options(resultSetType ResultSetType.FORWARD_ONLY, fetchSize 1000) ResultType(LargeData.class) void streamLargeData(ResultHandlerLargeData handler);