Spring JPA - Flere databaser

1. Oversigt

I denne vejledning implementerer vi en simpel Spring-konfiguration til en Spring Data JPA-system med flere databaser.

2. Enhederne

Først - lad os oprette to enkle enheder - hver bor i en separat database.

Her er den første “Bruger" enhed:

pakke com.baeldung.multipledb.model.user; @Entity @Table (skema = "brugere") offentlig klasse bruger {@Id @GeneratedValue (strategi = GenerationType.AUTO) privat int id; privat strengnavn; @Column (unik = true, nullable = false) privat streng-e-mail; privat int alder }

Og den anden enhed - “Produkt“:

pakke com.baeldung.multipledb.model.product; @Entity @Table (skema = "produkter") offentlig klasse Produkt {@Id privat int id; privat strengnavn; privat dobbelt pris; }

Som du kan se, de to enheder placeres også i uafhængige pakker - dette vil være vigtigt, når vi bevæger os ind i konfigurationen.

3. JPA Repositories

Dernæst - lad os se på vores to JPA-arkiver - UserRepository:

pakke com.baeldung.multipledb.dao.user; offentlig grænseflade UserRepository udvider JpaRepository {}

Og ProductRepository:

pakke com.baeldung.multipledb.dao.product; offentlig grænseflade ProductRepository udvider JpaRepository {}

Bemærk igen, hvordan vi oprettede disse to arkiver i forskellige pakker.

4. Konfigurer JPA med Java

Næste - lad os komme til den faktiske forårskonfiguration. Vi starter med at oprette to konfigurationsklasser - en til Bruger og den anden til Produkt.

I hver af disse konfigurationsklasser skal vi definere følgende grænseflader til Bruger:

  • Datakilde
  • EntityManagerFactory (userEntityManager)
  • TransactionManager (userTransactionManager)

Lad os starte med at se på brugerkonfigurationen:

@Configuration @PropertySource ({"classpath: persistence-multiple-db.properties"}) @EnableJpaRepositories (basePackages = "com.baeldung.multipledb.dao.user", entityManagerFactoryRef = "userEntityManager", transactionManagerRefanagerRef = " PersistenceUserConfiguration {@Autowired private Environment env; @Bean @Primær offentlig LocalContainerEntityManagerFactoryBean userEntityManager () {LocalContainerEntityManagerFactoryBean em = ny LocalContainerEntityManagerFactoryBean (); em.setDataSource (userDataSource ()); em.setPackagesToScan (ny streng [] {"com.baeldung.multipledb.model.user"}); HibernateJpaVendorAdapter vendorAdapter = ny HibernateJpaVendorAdapter (); em.setJpaVendorAdapter (vendorAdapter); HashMap egenskaber = ny HashMap (); egenskaber.put ("hibernate.hbm2ddl.auto", env.getProperty ("hibernate.hbm2ddl.auto")); egenskaber.put ("hibernate.dialect", env.getProperty ("hibernate.dialect")); em.setJpaPropertyMap (egenskaber); returner dem; } @Primary @Bean offentlig DataSource userDataSource () {DriverManagerDataSource dataSource = ny DriverManagerDataSource (); dataSource.setDriverClassName (env.getProperty ("jdbc.driverClassName")); dataSource.setUrl (env.getProperty ("bruger.jdbc.url")); dataSource.setUsername (env.getProperty ("jdbc.user")); dataSource.setPassword (env.getProperty ("jdbc.pass")); returnere datakilde; } @Primary @Bean offentlig PlatformTransactionManager userTransactionManager () {JpaTransactionManager transactionManager = ny JpaTransactionManager (); transactionManager.setEntityManagerFactory (userEntityManager (). getObject ()); returtransaktionManager; }}

Bemærk hvordan vi bruger userTransactionManager som vores Primær TransactionManager - ved at kommentere bønnedefinitionen med @Primær. Det er nyttigt, når vi implicit eller eksplicit skal injicere transaktionsadministratoren uden at specificere hvilken ved navn.

Lad os derefter diskutere PersistenceProductConfiguration - hvor vi definerer lignende bønner:

@Configuration @PropertySource ({"classpath: persistence-multiple-db.properties"}) @EnableJpaRepositories (basePackages = "com.baeldung.multipledb.dao.product", entityManagerFactoryRef = "productEntityManager", transaktionManagerRefanagerRef = "produkt" PersistenceProductConfiguration {@Autowired private Environment env; @Bean public LocalContainerEntityManagerFactoryBean productEntityManager () {LocalContainerEntityManagerFactoryBean em = ny LocalContainerEntityManagerFactoryBean (); em.setDataSource (productDataSource ()); em.setPackagesToScan (ny streng [] {"com.baeldung.multipledb.model.product"}); HibernateJpaVendorAdapter vendorAdapter = ny HibernateJpaVendorAdapter (); em.setJpaVendorAdapter (vendorAdapter); HashMap egenskaber = ny HashMap (); egenskaber.put ("dvale.hbm2ddl.auto", env.getProperty ("dvale.hbm2ddl.auto")); egenskaber.put ("hibernate.dialect", env.getProperty ("hibernate.dialect")); em.setJpaPropertyMap (egenskaber); returner dem; } @Bean public DataSource productDataSource () {DriverManagerDataSource dataSource = ny 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")); returnere datakilde; } @Bean offentlig PlatformTransactionManager productTransactionManager () {JpaTransactionManager transactionManager = ny JpaTransactionManager (); transactionManager.setEntityManagerFactory (productEntityManager (). getObject ()); returtransaktionManager; }}

5. Enkel test

Endelig - lad os teste vores konfigurationer.

Vi vil prøve en simpel test ved at oprette en forekomst af hver enhed og sørge for, at den oprettes - som i følgende eksempel:

@RunWith (SpringRunner.class) @SpringBootTest @EnableTransactionManagement public class JpaMultipleDBIntegrationTest {@Autowired private UserRepository userRepository; @Autowired privat ProductRepository productRepository; @Test @Transactional ("userTransactionManager") offentlig ugyldig nårCreatingUser_thenCreated () {User user = new User (); user.setName ("John"); user.setEmail ("[email protected]"); user.setAge (20); bruger = userRepository.save (bruger); assertNotNull (userRepository.findOne (user.getId ())); } @Test @Transactional ("userTransactionManager") offentlig ugyldig nårCreatingUsersWithSameEmail_thenRollback () {User user1 = new User (); user1.setName ("John"); user1.setEmail ("[email protected]"); bruger1.setAge (20); bruger1 = brugerRepository.save (bruger1); assertNotNull (userRepository.findOne (user1.getId ())); Brugerbruger2 = ny bruger (); user2.setName ("Tom"); user2.setEmail ("[email protected]"); bruger2.setAge (10); prøv {user2 = userRepository.save (user2); } fange (DataIntegrityViolationException e) {} assertNull (userRepository.findOne (user2.getId ())); } @Test @Transactional ("productTransactionManager") offentlig ugyldig nårCreatingProduct_thenCreated () {Produkt produkt = nyt produkt (); product.setName ("Bog"); product.setId (2); product.setPrice (20); produkt = productRepository.save (produkt); assertNotNull (productRepository.findOne (product.getId ())); }}

6. Flere databaser i Spring Boot

Spring Boot kan forenkle konfigurationen ovenfor.

Som standard, Spring Boot vil starte sin standard Datakilde med konfigurationsegenskaberne forud for spring.datasource. *:

spring.datasource.jdbcUrl = [url] spring.datasource.username = [brugernavn] spring.datasource.password = [password]

Vi vil nu fortsætte med at bruge den samme måde at konfigurer det andet Datakilde, men med et andet egenskabsnavneområde:

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

Fordi vi ønsker, at Spring Boot-autokonfigurationen skal samle de forskellige egenskaber op (og instantiere to forskellige Data kilder), definerer vi to konfigurationsklasser svarende til dem i de foregående sektioner:

@Configuration @PropertySource ({"classpath: persistence-multiple-db-boot.properties"}) @EnableJpaRepositories (basePackages = "com.baeldung.multipledb.dao.user", entityManagerFactoryRef = "userEntityManager", transaktionManagerRanagerRanagerRef = "userEntityManager", offentlig klasse PersistenceUserAutoConfiguration {@Primary @Bean @ConfigurationProperties (prefix = "spring.datasource") public DataSource userDataSource () {return DataSourceBuilder.create (). build (); } // userEntityManager bønne // userTransactionManager bønne}
@Configuration @PropertySource ({"classpath: persistence-multiple-db-boot.properties"}) @EnableJpaRepositories (basePackages = "com.baeldung.multipledb.dao.product", entityManagerFactoryRef = "productEntityManager", transactionManagerRanagerRanagerRan = TransManagerFan offentlig klasse PersistenceProductAutoConfiguration {@Bean @ConfigurationProperties (prefix = "spring.second-datasource") public DataSource productDataSource () {return DataSourceBuilder.create (). build (); } // productEntityManager bønne // productTransactionManager bønne} 

Vi har defineret datakildeegenskaberne indeni vedholdenhed- flere-db-boot.egenskaber i henhold til konventionen om automatisk konfiguration af boot.

Den interessante del er kommentere metoden til oprettelse af datakildebønne med @ConfigurationProperties. Vi skal bare angive det tilsvarende konfigurationspræfiks. Inde i denne metode bruger vi en DataSourceBuilder, og Spring Boot tager sig automatisk af resten.

Men hvordan injiceres de konfigurerede egenskaber i Datakilde konfiguration?

Når du ringer til bygge () metode til DataSourceBuilder, det kalder det privat binde() metode:

public T build () {Class type = getType (); DataSource resultat = BeanUtils.instantiateClass (type); maybeGetDriverClassName (); bind (resultat); returnere (T) resultat; }

Denne private metode udfører meget af den autokonfigurationsmagi, der binder den løste konfiguration til den aktuelle Datakilde eksempel:

private void bind (DataSource result) {ConfigurationPropertySource source = new MapConfigurationPropertySource (this.properties); ConfigurationPropertyNameAliases aliases = nye ConfigurationPropertyNameAliases (); aliases.addAliases ("url", "jdbc-url"); aliases.addAliases ("brugernavn", "bruger"); Bindemiddelbinder = nyt bindemiddel (kilde.medAliaser (aliaser)); binder.bind (ConfigurationPropertyName.EMPTY, Bindable.ofInstance (resultat)); }

Selvom vi ikke selv behøver at røre ved denne kode, er det stadig nyttigt at vide, hvad der sker under hætten på Spring Boot-autokonfigurationen.

Ud over dette er Transaction Manager og Entity Manager bønnekonfigurationen den samme som standard Spring-applikationen.

7. Konklusion

Denne artikel var en praktisk oversigt over, hvordan du konfigurerer dit Spring Data JPA-projekt til at bruge flere databaser.

Det fuld implementering af denne artikel kan findes i GitHub-projektet - dette er et Maven-baseret projekt, så det skal være let at importere og køre som det er.


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