无persistence.xml的Spring MVC 4多EntityManagerFactory配置问询
Got it, let's walk through exactly how to set up multiple EntityManagerFactory beans in your Spring MVC 4 project—since you're using Java config instead of persistence.xml, this is totally doable with a few key tweaks.
Step 1: Define Separate Data Sources
First, you'll need a dedicated DataSource bean for each database you want to connect to. These will power their corresponding EntityManagerFactory instances.
package test.conf; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import javax.sql.DataSource; @Configuration public class DataSourceConfig { // Primary data source (marked as default when no qualifier is specified) @Primary @Bean(name = "primaryDataSource") public DataSource primaryDataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/primary_db"); dataSource.setUsername("root"); dataSource.setPassword("password"); return dataSource; } // Secondary data source for your second database @Bean(name = "secondaryDataSource") public DataSource secondaryDataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("org.postgresql.Driver"); dataSource.setUrl("jdbc:postgresql://localhost:5432/secondary_db"); dataSource.setUsername("postgres"); dataSource.setPassword("postgres"); return dataSource; } }
Step 2: Create Corresponding EntityManagerFactory Beans
Next, build an EntityManagerFactory for each data source. Make sure to:
- Use unique bean names
- Link the correct
DataSourcewith@Qualifier - Scan only entity classes specific to each database (avoids cross-database entity conflicts)
- Set JPA properties tailored to each database's dialect and behavior
package test.conf; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.beans.factory.annotation.Qualifier; import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; import java.util.Properties; @Configuration public class JpaConfig { // Primary EntityManagerFactory (default) @Primary @Bean(name = "primaryEntityManagerFactory") public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory( @Qualifier("primaryDataSource") DataSource dataSource) { LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(dataSource); em.setPackagesToScan("test.entity.primary"); // Entities belonging to primary DB HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); em.setJpaVendorAdapter(vendorAdapter); Properties jpaProperties = new Properties(); jpaProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect"); jpaProperties.setProperty("hibernate.hbm2ddl.auto", "update"); em.setJpaProperties(jpaProperties); return em; } // Secondary EntityManagerFactory @Bean(name = "secondaryEntityManagerFactory") public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory( @Qualifier("secondaryDataSource") DataSource dataSource) { LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(dataSource); em.setPackagesToScan("test.entity.secondary"); // Entities belonging to secondary DB HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); em.setJpaVendorAdapter(vendorAdapter); Properties jpaProperties = new Properties(); jpaProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect"); jpaProperties.setProperty("hibernate.hbm2ddl.auto", "validate"); em.setJpaProperties(jpaProperties); return em; } }
Step 3: Add Transaction Managers for Each EntityManagerFactory
Each EntityManagerFactory needs its own PlatformTransactionManager to handle transactions for that database.
package test.conf; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.transaction.PlatformTransactionManager; import javax.persistence.EntityManagerFactory; @Configuration public class TransactionConfig { @Primary @Bean(name = "primaryTransactionManager") public PlatformTransactionManager primaryTransactionManager( @Qualifier("primaryEntityManagerFactory") EntityManagerFactory emf) { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(emf); return transactionManager; } @Bean(name = "secondaryTransactionManager") public PlatformTransactionManager secondaryTransactionManager( @Qualifier("secondaryEntityManagerFactory") EntityManagerFactory emf) { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(emf); return transactionManager; } }
Step 4: Use the Correct EntityManager/Transaction Manager in Your Code
When working with a specific database, use @Qualifier or unitName to inject the right EntityManager, and specify the matching transaction manager in @Transactional.
Example DAO for Secondary Database:
package test.dao; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import test.entity.secondary.SecondaryEntity; @Repository public class SecondaryDao { @PersistenceContext(unitName = "secondaryEntityManagerFactory") private EntityManager entityManager; @Transactional(value = "secondaryTransactionManager") public void saveSecondaryEntity(SecondaryEntity entity) { entityManager.persist(entity); } }
For Spring Data JPA Repositories:
Configure separate repository scans with explicit references to the correct EntityManagerFactory and TransactionManager:
@Configuration @EnableJpaRepositories( basePackages = "test.repository.primary", entityManagerFactoryRef = "primaryEntityManagerFactory", transactionManagerRef = "primaryTransactionManager" ) @EnableJpaRepositories( basePackages = "test.repository.secondary", entityManagerFactoryRef = "secondaryEntityManagerFactory", transactionManagerRef = "secondaryTransactionManager" ) public class JpaRepositoryConfig { // No extra beans needed here if already defined above }
Key Reminders:
- Use distinct bean names and
@Qualifierto avoid ambiguity between beans @Primarymarks one bean as the default when no qualifier is specified—optional but helpful if most of your code uses one database- Keep entity classes for different databases in separate packages to prevent unintended scanning by the wrong
EntityManagerFactory
内容的提问来源于stack exchange,提问作者marionmaiden

