在开始集成MybatisPlus之前,建议先创建一个干净的项目备份。我遇到过不少开发者因为直接修改生产环境代码导致问题难以回退的情况。RuoYi-Vue 3.8.6默认使用的是原生MyBatis,我们需要先确认当前项目的依赖状态。
打开ruoyi-common模块下的pom.xml文件,找到原有的MyBatis依赖项。通常你会看到类似这样的配置:
xml复制<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
这里有个关键决策点:是直接替换还是共存?根据我的实践经验,建议先保留原依赖,等完全迁移完成后再移除。这样可以避免中途出现问题导致项目无法启动。
接下来添加MybatisPlus的核心依赖。注意版本选择很重要,我测试过3.5.3.1版本与RuoYi-Vue 3.8.6兼容性最好:
xml复制<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
这里有个小技巧:如果你不确定该用哪个版本,可以到Maven中央仓库查看该依赖的最新release版本。但要注意,最新版不一定最稳定,特别是对于已有项目升级的情况。
在ruoyi-framework模块的config包下,我们需要新建一个MybatisPlusConfig配置类。这个类将替代原有的MyBatisConfig(但先不要删除旧配置)。
我建议采用渐进式改造策略:
以下是完整的配置类示例,我添加了详细的注释说明每个插件的用途:
java复制@EnableTransactionManagement(proxyTargetClass = true)
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件 - 必选
interceptor.addInnerInterceptor(paginationInnerInterceptor());
// 乐观锁插件 - 按需
interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor());
// SQL阻断插件 - 安全防护
interceptor.addInnerInterceptor(blockAttackInnerInterceptor());
return interceptor;
}
private PaginationInnerInterceptor paginationInnerInterceptor() {
PaginationInnerInterceptor pagination = new PaginationInnerInterceptor();
// 设置数据库类型为MySQL
pagination.setDbType(DbType.MYSQL);
// 单页最大500条,-1表示不受限
pagination.setMaxLimit(500L);
// 溢出总页数后是否处理
pagination.setOverflow(true);
return pagination;
}
private OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() {
return new OptimisticLockerInnerInterceptor();
}
private BlockAttackInnerInterceptor blockAttackInnerInterceptor() {
return new BlockAttackInnerInterceptor();
}
}
现在需要处理application.yml中的配置。MybatisPlus保持了与MyBatis的高度兼容性,所以配置项基本可以一一对应迁移。
原MyBatis配置:
yaml复制mybatis:
typeAliasesPackage: com.ruoyi.**.domain
mapperLocations: classpath*:mapper/**/*Mapper.xml
configLocation: classpath:mybatis/mybatis-config.xml
对应的MybatisPlus配置:
yaml复制mybatis-plus:
typeAliasesPackage: com.ruoyi.**.domain
mapperLocations: classpath*:mapper/**/*Mapper.xml
configLocation: classpath:mybatis/mybatis-config.xml
这里有个重要细节:如果你项目中有自定义的mybatis-config.xml文件,需要检查其中是否有与MybatisPlus插件冲突的配置。特别是关于分页、缓存的设置,建议优先使用MybatisPlus提供的配置方式。
MybatisPlus的Mapper接口需要继承BaseMapper
java复制public interface SysUserMapper extends BaseMapper<SysUser> {
// 原有自定义方法可以保留
List<SysUser> selectUserList(SysUser user);
// 自动获得CRUD方法
// selectById, selectBatchIds, insert, updateById等
}
改造后,你立即获得了数十个常用的CRUD方法,无需再写对应的XML映射。但要注意,原有的自定义SQL查询仍然需要保留XML映射文件。
在Service层,我们可以利用MybatisPlus提供的IService接口和ServiceImpl实现类来简化代码。例如用户服务:
java复制public interface ISysUserService extends IService<SysUser> {
// 原有业务方法
List<SysUser> selectUserList(SysUser user);
// 自动获得批量操作方法
// saveBatch, updateBatchById等
}
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {
@Override
public List<SysUser> selectUserList(SysUser user) {
// 原有实现逻辑
}
// 自动获得基础CRUD实现
}
这种改造方式是非侵入式的,原有业务逻辑完全不受影响,同时又能享受MybatisPlus带来的便利。
首先验证最基本的增删改查功能是否正常。我通常会创建一个简单的测试用例:
java复制@SpringBootTest
public class UserCrudTest {
@Autowired
private SysUserMapper userMapper;
@Test
public void testBasicCrud() {
// 新增测试
SysUser user = new SysUser();
user.setUserName("testUser");
user.setNickName("测试用户");
Assertions.assertEquals(1, userMapper.insert(user));
// 查询测试
SysUser dbUser = userMapper.selectById(user.getUserId());
Assertions.assertEquals("testUser", dbUser.getUserName());
// 更新测试
dbUser.setNickName("修改后的昵称");
Assertions.assertEquals(1, userMapper.updateById(dbUser));
// 删除测试
Assertions.assertEquals(1, userMapper.deleteById(dbUser.getUserId()));
}
}
分页是MybatisPlus的强项,但也是最容易出问题的部分。RuoYi-Vue前端表格依赖后端分页,需要特别注意:
java复制@Test
public void testPageQuery() {
Page<SysUser> page = new Page<>(1, 10); // 第一页,每页10条
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
wrapper.like(SysUser::getUserName, "admin");
Page<SysUser> result = userMapper.selectPage(page, wrapper);
Assertions.assertEquals(10, result.getSize());
Assertions.assertTrue(result.getTotal() > 0);
}
在实际项目中,你可能会遇到分页总数不正确的问题。这通常是由于没有正确配置分页插件或者SQL中包含了GROUP BY等影响计数结果的语句。
根据项目需求,你可能还需要测试:
每个功能都需要编写对应的测试用例。例如测试乐观锁:
java复制@Test
public void testOptimisticLock() {
SysUser user = userMapper.selectById(1L);
String originalName = user.getUserName();
// 模拟并发修改
user.setUserName("修改1");
userMapper.updateById(user);
user.setUserName(originalName);
// 应该抛出OptimisticLockException
Assertions.assertThrows(OptimisticLockException.class, () -> {
userMapper.updateById(user);
});
}
在实际升级过程中,我遇到过几个典型问题,这里分享解决方案:
问题1:启动时报错"Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required"
这是因为Spring容器中存在多个MyBatis相关Bean导致的冲突。解决方案是在主配置类上排除原生MyBatis的自动配置:
java复制@SpringBootApplication(exclude = {MybatisAutoConfiguration.class})
问题2:分页查询返回结果为空但SQL在数据库中执行正常
这通常是由于分页插件没有正确配置导致的。检查以下几点:
问题3:自定义SQL在XML中不生效
MybatisPlus默认会先查找接口方法对应的XML映射,如果找不到才会尝试使用内置方法。检查:
问题4:字段自动填充不工作
如果需要自动填充创建时间、更新时间等字段,需要:
完成基本集成后,可以考虑以下几个优化方向:
java复制@Bean
@Profile({"dev", "test"}) // 只在开发和测试环境启用
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor interceptor = new PerformanceInterceptor();
interceptor.setMaxTime(1000); // SQL执行最大时长,超过自动停止
interceptor.setFormat(true); // 格式化SQL
return interceptor;
}
二级缓存优化:合理配置MybatisPlus的二级缓存,注意与Spring Cache的配合
批量操作优化:使用MybatisPlus的批量操作方法替代循环单条操作
java复制// 不好的做法
for(User user : userList) {
userMapper.insert(user);
}
// 推荐做法
userService.saveBatch(userList);
java复制// 传统方式
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("user_name", "admin");
// Lambda方式
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getUserName, "admin");
为了确保升级过程万无一失,我总结了一个检查清单:
在实际项目中,我建议分阶段进行升级:先在测试环境验证,然后灰度发布到生产环境,最后全量升级。每次升级后都要运行完整的测试套件,确保系统稳定性。