news 2026/9/20 10:51:49

Spring Boot 3.3与MyBatis-Plus整合实战与优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring Boot 3.3与MyBatis-Plus整合实战与优化

1. 项目背景与核心价值

Spring Boot 3.3.X作为当前Java生态中最主流的应用开发框架,其与MyBatis-Plus的组合堪称企业级开发的黄金搭档。最近在重构一个老项目时,我再次验证了这套技术栈的威力——原本需要200行的JDBC模板代码,用MyBatis-Plus只需要10行注解就能搞定。这种开发效率的提升对于应对互联网时代快速迭代的需求至关重要。

MyBatis-Plus 3.5.3+版本针对Spring Boot 3.x的自动配置做了深度优化,特别是在动态数据源、多租户等企业级场景下表现出色。本文将基于最新稳定版演示如何实现二者的无缝整合,并分享我在实际项目中总结的五个关键配置技巧。

2. 环境准备与工程搭建

2.1 依赖配置要点

创建Spring Boot项目时,建议使用最新的3.3.0版本。在pom.xml中需要特别注意以下依赖项:

<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> <!-- 必须添加的配套依赖 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.5.3.1</version> <scope>compile</scope> </dependency>

重要提示:Spring Boot 3.x默认使用Jakarta EE 9+,需要确保所有相关依赖(如JDBC驱动)也兼容Jakarta命名空间。常见的坑是引入老版本的druid等连接池会导致类加载冲突。

2.2 配置文件关键参数

在application.yml中,以下配置项直接影响MyBatis-Plus的行为:

mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开发环境建议开启 map-underscore-to-camel-case: true # 必须开启的驼峰转换 global-config: db-config: logic-delete-field: deleted # 逻辑删除字段名 logic-not-delete-value: 0 logic-delete-value: 1

3. 核心功能实现详解

3.1 实体类与Mapper配置

实体类定义时需要特别注意Lombok注解与MyBatis-Plus注解的配合:

@Data @TableName(value = "sys_user", autoResultMap = true) public class User { @TableId(type = IdType.AUTO) private Long id; @TableField(value = "user_name", condition = SqlCondition.LIKE) private String username; @TableLogic private Integer deleted; }

Mapper接口只需要继承BaseMapper即可获得CRUD能力:

@Mapper public interface UserMapper extends BaseMapper<User> { // 自定义方法示例 @Select("SELECT * FROM sys_user WHERE age > #{age}") List<User> selectByAge(@Param("age") Integer age); }

3.2 分页插件最佳实践

分页配置需要特别注意高并发场景下的优化:

@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 分页插件(必须放在第一位) interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL){ @Override public void optimizeCount(boolean optimizeCount) { // 大数据量时关闭count优化 if(tableSize > 1000000) { super.optimizeCount(false); } } }); // 乐观锁插件 interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; } }

4. 高级特性实战

4.1 动态表名处理

在SAAS多租户系统中,动态表名是常见需求。通过实现TableNameHandler接口:

public class TenantTableNameHandler implements TableNameHandler { private final ThreadLocal<String> tenantId = new ThreadLocal<>(); @Override public String dynamicTableName(String sql, String tableName) { return Optional.ofNullable(tenantId.get()) .map(id -> id + "_" + tableName) .orElse(tableName); } }

然后在配置类中注册:

@Bean public DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor() { DynamicTableNameInnerInterceptor interceptor = new DynamicTableNameInnerInterceptor(); interceptor.setTableNameHandler(new TenantTableNameHandler()); return interceptor; }

4.2 多数据源配置

结合Spring Boot的AbstractRoutingDataSource实现:

@Configuration @MapperScan(basePackages = "com.example.mapper") public class DataSourceConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.master") public DataSource masterDataSource() { return DruidDataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.slave") public DataSource slaveDataSource() { return DruidDataSourceBuilder.create().build(); } @Bean public DataSource dynamicDataSource() { Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put("master", masterDataSource()); targetDataSources.put("slave", slaveDataSource()); return new DynamicDataSource(masterDataSource(), targetDataSources); } }

5. 性能优化与问题排查

5.1 SQL注入防护

MyBatis-Plus虽然提供了Wrapper构建安全查询,但仍需注意:

// 错误示例(存在注入风险) QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.apply("date_format(create_time,'%Y-%m-%d') = '" + date + "'"); // 正确写法 wrapper.apply("date_format(create_time,'%Y-%m-%d') = {0}", date);

5.2 批量操作优化

使用ExecuteBatch批量执行器可以显著提升性能:

@Test void testBatch() { String sqlStatement = "com.example.mapper.UserMapper.updateById"; SqlSessionFactory sqlSessionFactory = ...; try (SqlSession batchSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) { UserMapper mapper = batchSession.getMapper(UserMapper.class); for (int i = 0; i < 1000; i++) { User user = new User(); // ...set properties mapper.updateById(user); } batchSession.commit(); } }

6. 常见问题解决方案

6.1 类型处理器问题

处理JSON字段时推荐使用JacksonTypeHandler:

@TableField(typeHandler = JacksonTypeHandler.class) private Map<String, Object> attributes;

需要在配置类中注册:

@Bean public MybatisPlusSqlInjector mybatisPlusSqlInjector() { return new MybatisPlusSqlInjector() { @Override public List<AbstractJsonTypeHandler<?>> getTypeHandlers() { return Arrays.asList( new JacksonTypeHandler(), new FastjsonTypeHandler() ); } }; }

6.2 事务失效场景

多数据源环境下需要明确指定事务管理器:

@Transactional(transactionManager = "masterTransactionManager") public void businessMethod() { // 操作master数据源 masterMapper.insert(...); // 操作slave数据源 slaveMapper.select(...); }

在项目实际落地过程中,我发现合理使用MyBatis-Plus的Lambda表达式可以大幅提升代码可读性。特别是在复杂查询场景下,相比原生MyBatis的XML配置方式,LambdaQueryWrapper能让代码逻辑更集中、更类型安全。比如处理多表关联查询时,可以这样构建查询条件:

List<User> users = userMapper.selectList(new LambdaQueryWrapper<User>() .eq(User::getStatus, 1) .inSql(User::getDeptId, "SELECT id FROM sys_dept WHERE status = 1") .orderByDesc(User::getCreateTime) .last("LIMIT 10"));

这种链式调用的写法不仅直观,还能利用IDE的代码提示和编译时类型检查,有效减少运行时错误。对于需要频繁变动的查询条件,建议封装成Builder模式,进一步提高代码的可维护性。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 6:34:07

基于SpringBoot+Vue的医护人员排班管理系统设计与实践

排班问题在每个医院科室里都是月月要经历的折磨。护士长每个月末拿着纸质排班表对着住院人次和护士休假日程反复权衡&#xff0c;医生们为了换班在群里来回协调&#xff0c;最后排出来的表还是有人不满意。一个基于SpringBootVue的医护人员排班管理系统&#xff0c;就是把这些线…

作者头像 李华
网站建设 2026/9/20 5:03:08

GeoScene Pro连接人大金仓KingbaseES实操:ODBC配置与空间数据入库要点

最近在配合一个空间数据管理平台的项目时&#xff0c;客户明确要求数据底座用人大金仓 KingbaseES&#xff0c;前端负责制图、编辑和数据发布的是 GeoScene 系列&#xff0c;主力就是 GeoScene Pro。这套组合不像 ArcGIS PostgreSQL 那样开箱即用&#xff0c;资料也散&#xf…

作者头像 李华
网站建设 2026/9/19 5:23:14

OpenEuler 时间同步实战:用 chrony 配置与管理服务器时间

OpenEuler 这款系统我用得比较多&#xff0c;最初接手一批 22.03 SP3 的服务器时&#xff0c;第一件事不是装业务&#xff0c;而是先把时间同步搞定。原因很简单&#xff1a;证书校验、日志审计、数据库复制、分布式调度&#xff0c;哪一样都依赖服务器时间。如果机器之间时间差…

作者头像 李华
网站建设 2026/9/20 5:05:39

Colibri浏览器:基于Gecko内核的极简键盘流与定制指南

1. 项目概述与设计定位Colibri&#xff0c;这个词第一眼看上去像某个法语单词&#xff0c;实际上它来自西班牙语和法语&#xff0c;意思是“蜂鸟”。在软件工程圈里&#xff0c;叫这个名字的项目不止一个&#xff0c;有加密算法库&#xff0c;有嵌入式硬件模块&#xff0c;也有…

作者头像 李华
网站建设 2026/9/20 6:09:37

达梦数据库实时主备故障模拟演练全流程实战

“你们这个主备&#xff0c;到底能不能在关键时候顶上去&#xff1f;”——这句话我几乎每次给客户做达梦数据库架构评审都会被问到。DM数据库的实时主备集群确实能扛住单点故障&#xff0c;但“能扛”和“真正验证过能扛”是两码事。很多团队把主备部署完毕、监视器一切正常就…

作者头像 李华