最近在做一个基于 Spring Boot + MyBatis Plus 的 Maven 多模块项目时,遇到了一个很奇怪的问题:MyMetaObjectHandler 配置的自动填充日期功能失效了。简单来说,就是数据库表中的 create_time 和 update_time 字段本应该由 MyMetaObjectHandler 在插入和更新时自动填充,但实际写入数据库的却是 null。经过一番排查,最终解决了这个问题,这里记录一下。
问题场景重现
项目结构如下:
parent-module
├── common-module # 公共依赖和配置
├── dao-module # MyBatis Plus 相关配置和实体类
├── service-module # 业务逻辑
└── web-module # Controller
MyMetaObjectHandler 定义在 common-module 中,目的是为了在各个模块中共享。实体类定义在 dao-module 中,并且使用了 MyBatis Plus 的注解。在 web-module 中调用 service-module 的接口进行数据操作,期望 MyMetaObjectHandler 能够自动填充日期,但实际并没有生效。
底层原理深度剖析
MyBatis Plus 的 MetaObjectHandler 机制是通过拦截 MyBatis 的 Executor 接口来实现的。当执行 insert 或 update 操作时,MyBatis Plus 会检查是否存在实现了 MetaObjectHandler 接口的类,如果存在,则会调用其 insertFill 和 updateFill 方法。这两个方法可以对实体类的属性进行赋值,从而实现自动填充的功能。
失效的原因往往在于以下几个方面:
- 扫描路径配置错误:Spring Boot 默认只会扫描启动类所在包及其子包下的 Bean。如果
MyMetaObjectHandler没有被扫描到,Spring 容器就无法管理它,自然就无法生效。 - 配置类冲突:如果多个模块都配置了 MyBatis Plus 的相关配置,可能会导致配置冲突,从而影响
MetaObjectHandler的生效。特别是@MapperScan注解容易出现冲突。 - 事务管理问题:如果
insert或update操作没有被事务管理,可能会导致MetaObjectHandler在某些情况下无法正常工作。尤其是在涉及到多个数据源、分布式事务的情况下,更容易出现问题。 - 模块依赖问题:如果各个模块之间的依赖关系没有正确配置,可能会导致
MyMetaObjectHandler无法被正确加载。
代码和配置解决方案
针对上述可能的原因,需要逐一排查并解决。以下是一个可行的解决方案:
- 确保
MyMetaObjectHandler被 Spring 扫描到
在启动类或者配置类中,使用 @ComponentScan 注解指定 MyMetaObjectHandler 所在的包:
@SpringBootApplication
@ComponentScan({"com.example.common", "com.example.dao", "com.example.service", "com.example.web"})
public class WebApplication {
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
}
或者,在 common-module 的 Spring Boot 启动类上使用 @EnableAutoConfiguration 和 @ComponentScan,并确保 dao-module 和其他模块依赖 common-module。
- 避免配置类冲突
只在一个模块中配置 MyBatis Plus 的相关配置,例如在 dao-module 中。避免在多个模块中使用 @MapperScan 注解。如果需要在多个模块中使用 Mapper,可以将 Mapper 接口定义在 dao-module 中,并在其他模块中引用。
@Configuration
@MapperScan("com.example.dao.mapper") // 只在 dao-module 中配置
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
- 确保事务管理正确
使用 @Transactional 注解将 insert 和 update 操作纳入事务管理。如果涉及到多个数据源或分布式事务,需要使用相应的事务管理器。
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Transactional
@Override
public void saveUser(User user) {
userMapper.insert(user);
}
}
- 检查模块依赖关系
确保 web-module 依赖 service-module,service-module 依赖 dao-module,dao-module 依赖 common-module。在 pom.xml 文件中明确声明依赖关系,避免循环依赖。
<!-- web-module 的 pom.xml -->
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>service-module</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<!-- service-module 的 pom.xml -->
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>dao-module</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<!-- dao-module 的 pom.xml -->
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>common-module</artifactId>
<version>${project.version}</version>
</dependency>
<!-- MyBatis Plus 依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
</dependencies>
- 配置
MyMetaObjectHandler
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)
}
}
实战避坑经验总结
- 仔细检查包扫描路径:这是最常见的原因,也是最容易被忽略的。确保 Spring Boot 能够扫描到
MyMetaObjectHandler。 - 避免重复配置:在多模块项目中,尽量将配置集中在一个模块中,避免在多个模块中重复配置。
- 明确模块依赖关系:确保模块之间的依赖关系正确,避免循环依赖。可以使用 Maven 的 dependency:tree 命令来查看依赖树。
- 打印日志调试:在
MyMetaObjectHandler的insertFill和updateFill方法中添加日志输出,方便调试。 - 升级 MyBatis Plus 版本:如果使用的 MyBatis Plus 版本较低,可能会存在一些 Bug。尝试升级到最新版本。
- 仔细阅读官方文档:MyBatis Plus 的官方文档非常详细,遇到问题时可以查阅官方文档。
总之,解决 Maven多模块项目MyMetaObjectHandler自动填充日期未生效 的问题需要仔细分析,逐一排查。希望本文能够帮助到遇到类似问题的同学。
冠军资讯
代码一只喵