SpringBoot中CRUD Repository与EntityManager Factory关联机制探究
核心是Repository、实体、EntityManagerFactory三者的绑定关系,Spring Data JPA靠这个绑定来确定使用哪个EntityManager,具体拆解如下:
1. 实体与EntityManagerFactory的绑定
你每个模块配置的LocalContainerEntityManagerFactoryBean里,肯定指定了packagesToScan(扫描该模块的实体包),同时绑定了对应的DataSource。这意味着:
- 该EntityManagerFactory仅负责管理指定包下的实体
- 它的所有操作(包括从数据源获取连接)都基于你配置的模块专属数据源
比如模块A的EntityManagerFactory扫描com.modulea.entity,那这个工厂只会处理该包下的实体类,和其他模块的实体完全隔离。
2. Repository与EntityManagerFactory的绑定
Spring Data JPA通过@EnableJpaRepositories注解完成Repository和EntityManagerFactory的绑定:
- 在每个模块的配置类中添加
@EnableJpaRepositories时,你指定了basePackages(该模块的Repository包),同时通过entityManagerFactoryRef明确绑定对应的EntityManagerFactory Bean名称 - 该包下的所有Repository接口,都会默认使用这个EntityManagerFactory来获取EntityManager
举个实际配置示例:
@Configuration @EnableJpaRepositories( basePackages = "com.modulea.repository", entityManagerFactoryRef = "moduleAEntityManagerFactory", transactionManagerRef = "moduleATransactionManager" ) public class ModuleADataSourceConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.modulea") public DataSource moduleADataSource() { return DataSourceBuilder.create().build(); } @Bean public LocalContainerEntityManagerFactoryBean moduleAEntityManagerFactory(EntityManagerFactoryBuilder builder) { return builder .dataSource(moduleADataSource()) .packages("com.modulea.entity") .persistenceUnit("moduleAPersistenceUnit") .build(); } @Bean public PlatformTransactionManager moduleATransactionManager(EntityManagerFactory moduleAEntityManagerFactory) { return new JpaTransactionManager(moduleAEntityManagerFactory); } }
这里com.modulea.repository下的所有Repository,都会和moduleAEntityManagerFactory绑定,调用它们的save()方法时,自然会使用这个工厂生成的EntityManager。
3. 运行时的匹配流程
当你调用XxxRepository.save(entity)时:
- Spring Data JPA先找到当前Repository对应的EntityManagerFactory(即上述配置绑定的实例)
- 从该工厂获取EntityManager实例,这个EntityManager已经和模块对应的DataSource关联
- 用这个EntityManager执行实体持久化操作,最终操作对应的数据库
额外补充:如果项目中有多个EntityManagerFactory,但某个Repository未明确绑定,Spring会找标记了@Primary的EntityManagerFactory作为默认;如果没有@Primary且未明确绑定,会直接抛出“多个EntityManagerFactory存在”的异常——这也是你当前功能正常的原因:你已经通过配置完成了所有绑定。
内容的提问来源于stack exchange,提问作者Joel Mathew paul

