Spring JPA - Flere databaser

1. Oversikt

I denne opplæringen implementerer vi en enkel vårkonfigurasjon for en Spring Data JPA-system med flere databaser.

2. Enhetene

Først - la oss lage to enkle enheter - hver bor i en egen database.

Her er den første “Bruker”Enhet:

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

Og den andre enheten - “Produkt“:

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

Som du kan se, de to enhetene er også plassert i uavhengige pakker - Dette vil være viktig når vi går inn i konfigurasjonen.

3. JPA Repositories

Neste - la oss ta en titt på de to JPA-repositoriene våre - UserRepository:

pakke com.baeldung.multipledb.dao.user; offentlig grensesnitt UserRepository utvider JpaRepository {}

Og ProductRepository:

pakke com.baeldung.multipledb.dao.product; offentlig grensesnitt ProductRepository utvider JpaRepository {}

Merk igjen hvordan vi opprettet disse to arkivene i forskjellige pakker.

4. Konfigurer JPA med Java

Neste - la oss komme til den faktiske vårkonfigurasjonen. Vi starter med å sette opp to konfigurasjonsklasser - en for Bruker og den andre for Produkt.

I hver av disse konfigurasjonsklassene må vi definere følgende grensesnitt for Bruker:

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

La oss starte med å se på brukerkonfigurasjonen:

@Configuration @PropertySource ({"classpath: persistence-multiple-db.properties"}) @EnableJpaRepositories (basePackages = "com.baeldung.multipledb.dao.user", entityManagerFactoryRef = "userEntityManager", transactionManagerRefanagerRefanagerRef = " 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 egenskaper = nye HashMap (); properties.put ("dvalemodus.hbm2ddl.auto", env.getProperty ("dvalemodus.hbm2ddl.auto")); properties.put ("hibernate.dialect", env.getProperty ("hibernate.dialect")); em.setJpaPropertyMap (egenskaper); returnere dem; } @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")); returner datakilde; } @Primary @Bean offentlig PlatformTransactionManager userTransactionManager () {JpaTransactionManager transactionManager = ny JpaTransactionManager (); transactionManager.setEntityManagerFactory (userEntityManager (). getObject ()); returtransaksjonManager; }}

Legg merke til hvordan vi bruker userTransactionManager som vår Hoved TransactionManager - ved å kommentere bønnedefinisjonen med @Hoved. Det er nyttig når vi implisitt eller eksplisitt skal injisere transaksjonssjefen uten å spesifisere hvilken ved navn.

La oss diskutere PersistenceProductConfiguration - der vi definerer lignende bønner:

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

5. Enkel test

Til slutt - la oss teste konfigurasjonene våre.

Vi vil prøve en enkel test ved å opprette en forekomst av hver enhet og sørge for at den blir opprettet - 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); bruker = userRepository.save (bruker); assertNotNull (userRepository.findOne (user.getId ())); } @Test @Transactional ("userTransactionManager") offentlig ugyldig nårCreatingUsersWithSameEmail_thenRollback () {User user1 = new User (); user1.setName ("John"); bruker1.setEmail ("[e-postbeskyttet]"); bruker1.setAge (20); user1 = userRepository.save (user1); assertNotNull (userRepository.findOne (user1.getId ())); Bruker bruker2 = ny bruker (); user2.setName ("Tom"); user2.setEmail ("[email protected]"); bruker2.setAge (10); prøv {user2 = userRepository.save (user2); } fange (DataIntegrityViolationException e) {} assertNull (userRepository.findOne (user2.getId ())); } @Test @Transactional ("productTransactionManager") offentlig ugyldig nårCreatingProduct_thenCreated () {Produktprodukt = nytt produkt (); product.setName ("Book"); 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 konfigurasjonen ovenfor.

Som standard, Spring Boot vil starte standard Datakilde med konfigurasjonsegenskapene foran vår.datakilde. *:

spring.datasource.jdbcUrl = [url] spring.datasource.username = [brukernavn] spring.datasource.password = [passord]

Vi vil nå fortsette å bruke på samme måte konfigurer det andre Datakilde, men med et annet navneområde for eiendommer:

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

Fordi vi vil at Spring Boot-autokonfigurasjonen skal plukke opp de forskjellige egenskapene (og starte to forskjellige Datakilder), definerer vi to konfigurasjonsklasser som ligner på de i forrige seksjoner:

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

Vi har definert datakildeegenskapene inni utholdenhet- flere-db-boot.egenskaper i henhold til konvensjonen om oppstart av automatisk konfigurasjon.

Den interessante delen er kommentere datakildemetoden for oppretting av bønner med @ConfigurationProperties. Vi trenger bare å spesifisere det tilhørende konfigurasjonsprefikset. Inne i denne metoden bruker vi en DataSourceBuilder, og Spring Boot tar seg automatisk av resten.

Men hvordan blir de konfigurerte egenskapene injisert i Datakilde konfigurasjon?

Når du ringer til bygge() metoden på DataSourceBuilder, det vil kalle det private binde() metode:

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

Denne private metoden utfører mye av autokonfigurasjonsmagi, og binder den løste konfigurasjonen til den faktiske Datakilde forekomst:

private void bind (DataSource result) {ConfigurationPropertySource source = new MapConfigurationPropertySource (this.properties); ConfigurationPropertyNameAliases aliases = new ConfigurationPropertyNameAliases (); aliases.addAliases ("url", "jdbc-url"); aliases.addAliases ("brukernavn", "bruker"); Bindemiddel = nytt Bindemiddel (kilde.medAliaser (aliaser)); binder.bind (ConfigurationPropertyName.EMPTY, Bindable.ofInstance (result)); }

Selv om vi ikke trenger å berøre noen av denne koden selv, er det fortsatt nyttig å vite hva som skjer under panseret på Spring Boot-autokonfigurasjonen.

I tillegg til dette er Transaction Manager og Entity Manager bønnekonfigurasjonen den samme som standard Spring-applikasjonen.

7. Konklusjon

Denne artikkelen var en praktisk oversikt over hvordan du konfigurerer Spring Data JPA-prosjektet ditt til å bruke flere databaser.

De full gjennomføring av denne artikkelen finnes i GitHub-prosjektet - dette er et Maven-basert prosjekt, så det skal være enkelt å importere og kjøre som det er.


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