Spring Boot多数据源配置异常:仅主连接生效,实体未映射报错
问题本质
你的问题核心是两个数据源的EntityManagerFactory没有各自独立扫描对应包下的实体类,同时DAO层注入的EntityManager没有绑定到对应数据源的持久化单元,导致非主数据源的EntityManager无法识别对应库的实体,最终抛出org.hibernate.hql.internal.ast.QuerySyntaxException: <Entity_Name> is not mapped。
分步解决方案
1. 拆分数据源配置类,明确包扫描范围
给每个数据源单独写配置类,分别指定实体包、Repository包、持久化单元名称,只给其中一个数据源的核心Bean(DataSource、EntityManagerFactory、TransactionManager)加@Primary。
以MySQL为例:
@Configuration @EnableTransactionManagement @EnableJpaRepositories( basePackages = "com.victorqedu.mysql.repo", // MySQL专属Repository包 entityManagerFactoryRef = "mysqlEntityManagerFactory", transactionManagerRef = "mysqlTransactionManager" ) public class MysqlDataSourceConfig { @Primary @Bean(name = "mysqlDataSource") @ConfigurationProperties(prefix = "spring.datasource.mysql") public DataSource mysqlDataSource() { return DataSourceBuilder.create().build(); } @Primary @Bean(name = "mysqlEntityManagerFactory") public LocalContainerEntityManagerFactoryBean mysqlEntityManagerFactory( EntityManagerFactoryBuilder builder, @Qualifier("mysqlDataSource") DataSource dataSource) { return builder .dataSource(dataSource) .packages("com.victorqedu.mysql.entity") // MySQL实体类所在包 .persistenceUnit("mysqlPU") // 唯一持久化单元名称 .build(); } @Primary @Bean(name = "mysqlTransactionManager") public PlatformTransactionManager mysqlTransactionManager( @Qualifier("mysqlEntityManagerFactory") EntityManagerFactory entityManagerFactory) { return new JpaTransactionManager(entityManagerFactory); } }
PostgreSQL配置类类似,注意去掉@Primary,修改对应包路径和Bean名称:
@Configuration @EnableTransactionManagement @EnableJpaRepositories( basePackages = "com.victorqedu.postgresql.repo", entityManagerFactoryRef = "pgEntityManagerFactory", transactionManagerRef = "pgTransactionManager" ) public class PostgresqlDataSourceConfig { @Bean(name = "pgDataSource") @ConfigurationProperties(prefix = "spring.datasource.postgresql") public DataSource pgDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "pgEntityManagerFactory") public LocalContainerEntityManagerFactoryBean pgEntityManagerFactory( EntityManagerFactoryBuilder builder, @Qualifier("pgDataSource") DataSource dataSource) { return builder .dataSource(dataSource) .packages("com.victorqedu.postgresql.entity") .persistenceUnit("pgPU") .build(); } @Bean(name = "pgTransactionManager") public PlatformTransactionManager pgTransactionManager( @Qualifier("pgEntityManagerFactory") EntityManagerFactory entityManagerFactory) { return new JpaTransactionManager(entityManagerFactory); } }
2. DAO层绑定对应持久化单元的EntityManager
在DAO类中,通过@PersistenceContext的unitName参数指定对应数据源的持久化单元,确保注入的EntityManager是正确的:
@Repository public class MysqlUserDao { @PersistenceContext(unitName = "mysqlPU") private EntityManager entityManager; public List<MysqlUser> getAllUsers() { return entityManager.createQuery("SELECT u FROM MysqlUser u", MysqlUser.class) .getResultList(); } }
PostgreSQL的DAO同样指定unitName = "pgPU",不要用@Autowired直接注入EntityManager,否则会默认取主数据源的实例。
3. 核对application.properties配置
确保两个数据源的配置前缀和配置类中@ConfigurationProperties的prefix一致:
# MySQL配置 spring.datasource.mysql.url=jdbc:mysql://localhost:3306/testdb spring.datasource.mysql.username=root spring.datasource.mysql.password=yourpwd spring.datasource.mysql.driver-class-name=com.mysql.cj.jdbc.Driver # PostgreSQL配置 spring.datasource.postgresql.url=jdbc:postgresql://localhost:5432/testdb spring.datasource.postgresql.username=postgres spring.datasource.postgresql.password=yourpwd spring.datasource.postgresql.driver-class-name=org.postgresql.Driver # JPA通用配置 spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true
4. 确认包结构正确性
确保MySQL的实体类、Repository都在com.victorqedu.mysql下,PostgreSQL的在com.victorqedu.postgresql下,避免跨包导致扫描错误。
核心注意事项
- 每个
@EnableJpaRepositories必须明确basePackages,让Spring知道哪些Repository属于哪个数据源 - EntityManagerFactory的
packages参数必须指定对应实体包,保证Hibernate能映射对应库的表 - DAO层必须通过
unitName绑定正确的持久化单元,不能依赖默认注入
内容的提问来源于stack exchange,提问作者Victorqedu

