在本教程中,我们将为具有多个数据库的 Spring Data JPA 系统实现一个简单的 Spring 配置。
首先,让我们创建两个简单的实体,每个实体都位于单独的数据库中。
这是第一个User 实体:
package com.baeldung.multipledb.model.user;
@Entity @Table(schema = "users") public class User {
@Id @GeneratedValue(strategy = GenerationType.AUTO) private int id;
private String name;
@Column(unique = true, nullable = false) private String email;
private int age; }
|
这是第二个实体Product:
package com.baeldung.multipledb.model.product;
@Entity @Table(schema = "products") public class Product {
@Id private int id;
private String name;
private double price; }
|
我们可以看到,这两个实体也被放置在独立的包中。当我们进入配置时,这将很重要。
JPA 存储库
接下来,让我们看一下我们的两个 JPA 存储库UserRepository:
package com.baeldung.multipledb.dao.user;
public interface UserRepository extends JpaRepository<User, Integer> { }
|
和产品存储库:
package com.baeldung.multipledb.dao.product;
public interface ProductRepository extends JpaRepository<Product, Integer> { }
|
再次注意我们如何在不同的包中创建这两个存储库。
使用Java配置JPA
现在我们将开始实际的 Spring 配置。我们首先设置两个配置类 - 一个用于User,另一个用于Product。
在每个配置类中,我们需要为User定义以下接口:
- 数据源
- EntityManagerFactory(用户实体管理器)
- 事务管理器(用户事务管理器)
让我们首先查看用户配置:@Configuration @PropertySource({ "classpath:persistence-multiple-db.properties" }) @EnableJpaRepositories( basePackages = "com.baeldung.multipledb.dao.user", entityManagerFactoryRef = "userEntityManager", transactionManagerRef = "userTransactionManager" ) public class PersistenceUserConfiguration { @Autowired private Environment env; @Bean @Primary public LocalContainerEntityManagerFactoryBean userEntityManager() { LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(userDataSource()); em.setPackagesToScan( new String[] { "com.baeldung.multipledb.model.user" });
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); em.setJpaVendorAdapter(vendorAdapter); HashMap<String, Object> properties = new HashMap<>(); properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto")); properties.put("hibernate.dialect", env.getProperty("hibernate.dialect")); em.setJpaPropertyMap(properties);
return em; }
@Primary @Bean public DataSource userDataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName( env.getProperty("jdbc.driverClassName")); dataSource.setUrl(env.getProperty("user.jdbc.url")); dataSource.setUsername(env.getProperty("jdbc.user")); dataSource.setPassword(env.getProperty("jdbc.pass"));
return dataSource; }
@Primary @Bean public PlatformTransactionManager userTransactionManager() { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory( userEntityManager().getObject()); return transactionManager; } }
|
请注意我们如何通过使用@Primary注释 bean 定义来使用userTransactionManager作为我们的Primary TransactionManager。每当我们要隐式或显式注入事务管理器而不指定名称时,这都会很有帮助。
接下来,让我们讨论PersistenceProductConfiguration,我们在其中定义类似的 bean:
@Configuration @PropertySource({ "classpath:persistence-multiple-db.properties" }) @EnableJpaRepositories( basePackages = "com.baeldung.multipledb.dao.product", entityManagerFactoryRef = "productEntityManager", transactionManagerRef = "productTransactionManager" ) public class PersistenceProductConfiguration { @Autowired private Environment env;
@Bean public LocalContainerEntityManagerFactoryBean productEntityManager() { LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(productDataSource()); em.setPackagesToScan( new String[] { "com.baeldung.multipledb.model.product" });
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); em.setJpaVendorAdapter(vendorAdapter); HashMap<String, Object> properties = new HashMap<>(); properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto")); properties.put("hibernate.dialect", env.getProperty("hibernate.dialect")); em.setJpaPropertyMap(properties);
return em; }
@Bean public DataSource productDataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName( env.getProperty("jdbc.driverClassName")); dataSource.setUrl(env.getProperty("product.jdbc.url")); dataSource.setUsername(env.getProperty("jdbc.user")); dataSource.setPassword(env.getProperty("jdbc.pass"));
return dataSource; }
@Bean public PlatformTransactionManager productTransactionManager() { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory( productEntityManager().getObject()); return transactionManager; } }
|
Spring Boot 中的多个数据库
Spring Boot可以简化上面的配置。
默认情况下,Spring Boot 将使用以spring.datasource.*为前缀的配置属性实例化其默认DataSource:
spring.datasource.jdbcUrl = [url] spring.datasource.username = [username] spring.datasource.password = [password]
|
我们现在希望继续使用相同的方式来配置第二个DataSource,但使用不同的属性命名空间:
spring.second-datasource.jdbcUrl = [url] spring.second-datasource.username = [username] spring.second-datasource.password = [password]
|
因为我们希望 Spring Boot 自动配置获取这些不同的属性(并实例化两个不同的DataSources),所以我们将定义两个与前面部分类似的配置类:
@Configuration @PropertySource({"classpath:persistence-multiple-db-boot.properties"}) @EnableJpaRepositories( basePackages = "com.baeldung.multipledb.dao.user", entityManagerFactoryRef = "userEntityManager", transactionManagerRef = "userTransactionManager") public class PersistenceUserAutoConfiguration { @Primary @Bean @ConfigurationProperties(prefix="spring.datasource") public DataSource userDataSource() { return DataSourceBuilder.create().build(); } // userEntityManager bean
// userTransactionManager bean }
|
@Configuration @PropertySource({"classpath:persistence-multiple-db-boot.properties"}) @EnableJpaRepositories( basePackages = "com.baeldung.multipledb.dao.product", entityManagerFactoryRef = "productEntityManager", transactionManagerRef = "productTransactionManager") public class PersistenceProductAutoConfiguration { @Bean @ConfigurationProperties(prefix="spring.second-datasource") public DataSource productDataSource() { return DataSourceBuilder.create().build(); } // productEntityManager bean
// productTransactionManager bean }
|
现在我们已经根据引导自动配置约定在persistence-multiple-db-boot.properties中定义了数据源属性。
有趣的部分是使用@ConfigurationProperties注释数据源 bean 创建方法。我们只需要指定相应的配置前缀即可。在此方法中,我们使用 DataSourceBuilder , Spring Boot 将自动处理其余的事情。
但是如何将配置的属性注入到数据源配置中呢?
当在DataSourceBuilder上调用build()方法时,它将调用其私有的bind()方法:
public T build() { Class<? extends DataSource> type = getType(); DataSource result = BeanUtils.instantiateClass(type); maybeGetDriverClassName(); bind(result); return (T) result; }
|
这个私有方法执行大部分自动配置魔法,将解析的配置绑定到实际的DataSource实例:
private void bind(DataSource result) { ConfigurationPropertySource source = new MapConfigurationPropertySource(this.properties); ConfigurationPropertyNameAliases aliases = new ConfigurationPropertyNameAliases(); aliases.addAliases("url", "jdbc-url"); aliases.addAliases("username", "user"); Binder binder = new Binder(source.withAliases(aliases)); binder.bind(ConfigurationPropertyName.EMPTY, Bindable.ofInstance(result)); }
|
尽管我们不必亲自接触任何代码,但了解 Spring Boot 自动配置背后发生的情况仍然很有用。
除此之外,事务管理器和实体管理器 bean 配置与标准 Spring 应用程序相同。
结论
本文实用概述了如何配置 Spring Data JPA 项目以使用多个数据库。