Spring JPA - Meerdere databases

1. Overzicht

In deze tutorial implementeren we een eenvoudige Spring-configuratie voor een Spring Data JPA-systeem met meerdere databases.

2. De entiteiten

Laten we eerst twee eenvoudige entiteiten maken, die elk in een aparte database leven.

Hier is de eerste "Gebruiker" entiteit:

pakket com.baeldung.multipledb.model.user; @Entity @Table (schema = "gebruikers") openbare klasse Gebruiker {@Id @GeneratedValue (strategie = GenerationType.AUTO) privé int id; private String naam; @Column (uniek = waar, nullable = false) privé String-e-mail; privé int leeftijd; }

En de tweede entiteit - "Product“:

pakket com.baeldung.multipledb.model.product; @Entity @Table (schema = "products") openbare klasse Product {@Id privé int id; private String naam; particuliere dubbele prijs; }

Zoals je kunt zien, de twee entiteiten worden ook in onafhankelijke pakketten geplaatst - dit zal belangrijk zijn als we naar de configuratie gaan.

3. De PPV-opslagplaatsen

Vervolgens - laten we eens kijken naar onze twee JPA-repositories - UserRepository:

pakket com.baeldung.multipledb.dao.user; openbare interface UserRepository breidt JpaRepository {} uit

En Productopslagplaats:

pakket com.baeldung.multipledb.dao.product; openbare interface ProductRepository breidt JpaRepository {} uit

Merk nogmaals op hoe we deze twee repositories in verschillende pakketten hebben gemaakt.

4. Configureer JPA met Java

Vervolgens - laten we naar de daadwerkelijke Spring-configuratie gaan. We beginnen met het opzetten van twee configuratieklassen - een voor de Gebruiker en de andere voor de Product.

In elk van deze configuratieklassen moeten we de volgende interfaces definiëren voor Gebruiker:

  • Databron
  • EntityManagerFactory (userEntityManager)
  • TransactionManager (userTransactionManager)

Laten we beginnen met het bekijken van de gebruikersconfiguratie:

@Configuration @PropertySource ({"classpath: persistence-multiple-db.properties"}) @EnableJpaRepositories (basePackages = "com.baeldung.multipledb.dao.user", entityManagerFactoryRef = "userEntityManager", transactionManager classManager = "userTransactionManager" PersistenceUserConfiguration {@Autowired private Environment env; @Bean @ Primary openbaar LocalContainerEntityManagerFactoryBean userEntityManager () {LocalContainerEntityManagerFactoryBean em = nieuwe LocalContainerEntityManagerFactoryBean (); em.setDataSource (userDataSource ()); em.setPackagesToScan (nieuwe String [] {"com.baeldung.multipledb.model.user"}); HibernateJpaVendorAdapter vendorAdapter = nieuwe HibernateJpaVendorAdapter (); em.setJpaVendorAdapter (vendorAdapter); HashMap-eigenschappen = nieuwe HashMap (); properties.put ("hibernate.hbm2ddl.auto", env.getProperty ("hibernate.hbm2ddl.auto")); properties.put ("hibernate.dialect", env.getProperty ("hibernate.dialect")); em.setJpaPropertyMap (eigenschappen); terug em; } @Primary @Bean openbare DataSource userDataSource () {DriverManagerDataSource dataSource = nieuwe 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")); retourneer dataSource; } @Primary @Bean openbaar PlatformTransactionManager userTransactionManager () {JpaTransactionManager transactionManager = nieuwe JpaTransactionManager (); transactionManager.setEntityManagerFactory (userEntityManager (). getObject ()); return transactionManager; }}

Merk op hoe we de userTransactionManager Als onze Primair TransactionManager - door de bonendefinitie te annoteren met @Primair. Dat is handig wanneer we de transactiebeheerder impliciet of expliciet gaan injecteren zonder te specificeren welke bij naam.

Laten we het vervolgens bespreken PersistenceProductConfiguration - waar we vergelijkbare bonen definiëren:

@Configuration @PropertySource ({"classpath: persistence-multiple-db.properties"}) @EnableJpaRepositories (basePackages = "com.baeldung.multipledb.dao.product", entityManagerFactoryRef = "productEntityManager", transactionManager publicRefaction = "productTransactionManager" PersistenceProductConfiguration {@Autowired private Environment env; @Bean openbaar LocalContainerEntityManagerFactoryBean productEntityManager () {LocalContainerEntityManagerFactoryBean em = nieuwe LocalContainerEntityManagerFactoryBean (); em.setDataSource (productDataSource ()); em.setPackagesToScan (nieuwe String [] {"com.baeldung.multipledb.model.product"}); HibernateJpaVendorAdapter vendorAdapter = nieuwe HibernateJpaVendorAdapter (); em.setJpaVendorAdapter (vendorAdapter); HashMap-eigenschappen = nieuwe HashMap (); properties.put ("hibernate.hbm2ddl.auto", env.getProperty ("hibernate.hbm2ddl.auto")); properties.put ("hibernate.dialect", env.getProperty ("hibernate.dialect")); em.setJpaPropertyMap (eigenschappen); terug em; } @Bean openbare DataSource productDataSource () {DriverManagerDataSource dataSource = nieuwe 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")); retourneer dataSource; } @Bean openbaar PlatformTransactionManager productTransactionManager () {JpaTransactionManager transactionManager = nieuwe JpaTransactionManager (); transactionManager.setEntityManagerFactory (productEntityManager (). getObject ()); return transactionManager; }}

5. Eenvoudige test

Laten we tot slot onze configuraties testen.

We zullen een eenvoudige test proberen door van elke entiteit een instantie te maken en ervoor te zorgen dat deze wordt gemaakt, zoals in het volgende voorbeeld:

@RunWith (SpringRunner.class) @SpringBootTest @EnableTransactionManagement openbare klasse JpaMultipleDBIntegrationTest {@Autowired privé UserRepository userRepository; @Autowired privé ProductRepository productRepository; @Test @Transactional ("userTransactionManager") public void whenCreatingUser_thenCreated () {User user = nieuwe gebruiker (); user.setName ("John"); user.setEmail ("[e-mail beschermd]"); user.setAge (20); user = userRepository.save (gebruiker); assertNotNull (userRepository.findOne (user.getId ())); } @Test @Transactional ("userTransactionManager") public void whenCreatingUsersWithSameEmail_thenRollback () {User user1 = nieuwe gebruiker (); user1.setName ("John"); user1.setEmail ("[e-mail beschermd]"); user1.setAge (20); user1 = userRepository.save (gebruiker1); assertNotNull (userRepository.findOne (user1.getId ())); Gebruiker user2 = nieuwe gebruiker (); user2.setName ("Tom"); user2.setEmail ("[e-mail beschermd]"); user2.setAge (10); probeer {user2 = userRepository.save (user2); } catch (DataIntegrityViolationException e) {} assertNull (userRepository.findOne (user2.getId ())); } @Test @Transactional ("productTransactionManager") public void whenCreatingProduct_thenCreated () {Product product = nieuw product (); product.setName ("Boek"); product.setId (2); product.setPrice (20); product = productRepository.save (product); assertNotNull (productRepository.findOne (product.getId ())); }}

6. Meerdere databases in Spring Boot

Spring Boot kan de bovenstaande configuratie vereenvoudigen.

Standaard, Spring Boot zal de standaardinstelling starten Databron met de configuratie-eigenschappen voorafgegaan door spring.datasource. *:

spring.datasource.jdbcUrl = [url] spring.datasource.username = [gebruikersnaam] spring.datasource.password = [wachtwoord]

We willen nu dezelfde manier blijven gebruiken om configureer de tweede Databron, maar met een andere eigenschapsnaamruimte:

spring.second-datasource.jdbcUrl = [url] spring.second-datasource.username = [gebruikersnaam] spring.second-datasource.password = [wachtwoord]

Omdat we willen dat de autoconfiguratie van Spring Boot die verschillende eigenschappen oppikt (en twee verschillende Data bronnen), zullen we twee configuratieklassen definiëren die vergelijkbaar zijn met die in de vorige secties:

@Configuration @PropertySource ({"classpath: persistence-multiple-db-boot.properties"}) @EnableJpaRepositories (basePackages = "com.baeldung.multipledb.dao.user", entityManagerFactoryRef = "userEntityManager", "userEntityManager", "userEntityManager" openbare klasse PersistenceUserAutoConfiguration {@Primary @Bean @ConfigurationProperties (prefix = "spring.datasource") openbare 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", "productEntityManager", "productEntityManager" openbare klasse PersistenceProductAutoConfiguration {@Bean @ConfigurationProperties (prefix = "spring.second-datasource") openbare DataSource productDataSource () {retourneer DataSourceBuilder.create (). build (); } // productEntityManager bean // productTransactionManager bean} 

We hebben de eigenschappen van de gegevensbron binnen gedefinieerd persistence-multiple-db-boot.properties volgens de conventie voor automatische configuratie van opstarten.

Het interessante is annoteren van de methode voor het maken van gegevensbronbeans met @ConfigurationProperties. We hoeven alleen het bijbehorende configuratie-voorvoegsel op te geven. Binnen deze methode gebruiken we een DataSourceBuilder, en Spring Boot zorgt automatisch voor de rest.

Maar hoe worden de geconfigureerde eigenschappen geïnjecteerd in het Databron configuratie?

Wanneer u het bouwen() methode op de DataSourceBuilder, het zal zijn privé bellen binden() methode:

openbare T build () {Class type = getType (); DataSource-resultaat = BeanUtils.instantiateClass (type); misschienGetDriverClassName (); bind (resultaat); return (T) resultaat; }

Deze privémethode voert veel van de autoconfiguratiemagie uit, waarbij de opgeloste configuratie wordt gekoppeld aan de werkelijke Databron voorbeeld:

private void bind (DataSource-resultaat) {ConfigurationPropertySource source = nieuwe MapConfigurationPropertySource (this.properties); ConfigurationPropertyNameAliases aliassen = nieuwe ConfigurationPropertyNameAliases (); aliases.addAliases ("url", "jdbc-url"); aliases.addAliases ("gebruikersnaam", "gebruiker"); Binder binder = nieuwe Binder (source.withAliases (aliassen)); binder.bind (ConfigurationPropertyName.EMPTY, Bindable.ofInstance (resultaat)); }

Hoewel we deze code zelf niet hoeven aan te raken, is het toch handig om te weten wat er onder de motorkap van de Spring Boot-autoconfiguratie gebeurt.

Daarnaast is de configuratie van de bonen van Transaction Manager en Entity Manager hetzelfde als de standaard Spring-applicatie.

7. Conclusie

Dit artikel was een praktisch overzicht van hoe u uw Spring Data JPA-project configureert om meerdere databases te gebruiken.

De volledige implementatie van dit artikel is te vinden in het GitHub-project - dit is een op Maven gebaseerd project, dus het zou gemakkelijk te importeren en uit te voeren moeten zijn zoals het is.


$config[zx-auto] not found$config[zx-overlay] not found