SpringBoot多數(shù)據(jù)庫(kù)連接(mysql+oracle)的實(shí)現(xiàn)
出于業(yè)務(wù)需求,有時(shí)我們需要在spring boot web應(yīng)用程序中配置多個(gè)數(shù)據(jù)源并連接到多個(gè)數(shù)據(jù)庫(kù)。
使用過(guò)Spring Boot框架的小伙伴們,想必都發(fā)現(xiàn)了Spring Boot對(duì)JPA提供了非常好的支持,在開(kāi)發(fā)過(guò)程中可以很簡(jiǎn)潔的代碼輕松訪問(wèn)數(shù)據(jù)庫(kù),獲取我們想要的數(shù)據(jù)。
因此在這里,使用Spring Boot和JPA配置多個(gè)數(shù)據(jù)源的場(chǎng)景。
項(xiàng)目配置
在本文中,主要使用兩個(gè)不同的數(shù)據(jù)庫(kù),分別為:
- mysql(springboot)【primary,優(yōu)先搜尋該數(shù)據(jù)庫(kù)】:mysql數(shù)據(jù)庫(kù),包含User的信息
- oracle(springboot): oracle數(shù)據(jù)庫(kù), 包含Country信息
項(xiàng)目依賴
為了支持Mysql和Oracle數(shù)據(jù)庫(kù),我們必須要在pom.xml文件中添加相應(yīng)的依賴。
<dependencies> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version>11.2.0.3.0</version> <scope>compile</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>javax.persistence</groupId> <artifactId>javax.persistence-api</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> </dependency> </dependencies>
包管理
為了方便代碼的開(kāi)發(fā),我們將mysql和oracle分開(kāi)放在兩個(gè)不同的package下面,具體的包結(jié)構(gòu)如下:
將不同的模型分開(kāi)放入mysql和oracle包目錄下,需要注意的是,mysql和oracle為兩個(gè)不同的數(shù)據(jù)庫(kù),所以兩個(gè)數(shù)據(jù)庫(kù)中可能存在某個(gè)表名稱一致的場(chǎng)景。該場(chǎng)景下,會(huì)優(yōu)先匹配primary的數(shù)據(jù)庫(kù),如果該數(shù)據(jù)庫(kù)down了,才會(huì)匹配另外一張表。所以,如果想要兩張表都正常使用,建議使用不同的Entity名稱。
數(shù)據(jù)庫(kù)連接配置
我們?cè)趯傩晕募pplication.properties中分別配置兩個(gè)單獨(dú)的jdbc連接,將所有關(guān)聯(lián)的Entity類和Repository映射到兩個(gè)不同的包中。
## jdbc-primary spring.datasource.url=jdbc:mysql://localhost:33306/springboot?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false spring.datasource.username=springboot spring.datasource.password=123456 spring.ds_mysql.driverClassName=com.mysql.jdbc.Driver ## jdbc-second spring.second.datasource.url=jdbc:oracle:thin:@localhost:1909/xxx.xxx.com spring.second.datasource.userName=springboot spring.second.datasource.password=123456 spring.second.datasource.driver-class-name=oracle.jdbc.OracleDriver ## jpa spring.jpa.hibernate.ddl-auto=none spring.jpa.show-sql=true spring.jpa.properties.hibernate.jdbc.time_zone=UTC spring.jpa.properties.hibernate.jdbc.fetch_size=500 spring.jpa.properties.hibernate.jdbc.batch_size=100
數(shù)據(jù)源配置
需要注意的是,在配置多個(gè)數(shù)據(jù)源期間,必須將其中一個(gè)數(shù)據(jù)源標(biāo)記為primary,否則Spring Boot會(huì)檢測(cè)到多個(gè)類型的數(shù)據(jù)源,從而無(wú)法正常啟動(dòng)。
定義Data Source的Bean
想要?jiǎng)?chuàng)建Data Source,我們必須先實(shí)例化org.springframework.boot.autoconfigure.jdbc.DataSourceProperties類,加載application.properties文件中配置的數(shù)據(jù)庫(kù)連接信息,并通過(guò)DataSourceProperties對(duì)象的初始化builder方法創(chuàng)建一個(gè)javax.sql.DataSource對(duì)象。
primary Data Source
@Primary @Bean(name = "mysqlDataSourceProperties") @ConfigurationProperties("spring.datasource") public DataSourceProperties dataSourceProperties() { return new DataSourceProperties(); } @Primary @Bean(name = "mysqlDataSource") @ConfigurationProperties("spring.datasource.configuration") public DataSource dataSource (@Qualifier("mysqlDataSourceProperties") DataSourceProperties mysqlDataSourceProperties) { return mysqlDataSourceProperties.initializeDataSourceBuilder() .type(HikariDataSource.class) .build(); }
Secondary Data Source
@Bean(name = "oracleDataSourceProperties") @ConfigurationProperties("spring.second.datasource") public DataSourceProperties dataSourceProperties() { return new DataSourceProperties(); } @Bean @ConfigurationProperties("spring.second.datasource.configuration") public DataSource oracleDataSource(@Qualifier("oracleDataSourceProperties") DataSourceProperties oracleDataSourceProperties) { return oracleDataSourceProperties.initializeDataSourceBuilder() .type(HikariDataSource.class) .build(); }
我們使用@Qualifier注解,自動(dòng)關(guān)聯(lián)指定的DataSourceProperties.
定義實(shí)體類管理工廠的Bean
上面說(shuō)了,應(yīng)用程序使用Spring Data JPA的repository接口將我們從實(shí)體管理器(Entity Manager)中抽象出來(lái),從而進(jìn)行數(shù)據(jù)的訪問(wèn)。這里,我們使用org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean這個(gè)Bean來(lái)創(chuàng)建EM實(shí)例,后面利用這個(gè)EM實(shí)例與JPA entities進(jìn)行交互。
由于我們這里有兩個(gè)數(shù)據(jù)源,所以我要為每個(gè)數(shù)據(jù)源單獨(dú)創(chuàng)建一個(gè)EntityManagerFactory。
Primary Entity Manager Factory
@Primary @Bean(name = "mysqlEntityManagerFactory") public LocalContainerEntityManagerFactoryBean entityManagerFactory( EntityManagerFactoryBuilder builder, @Qualifier("mysqlDataSource") DataSource mysqlDataSource) { return builder.dataSource(mysqlDataSource) .packages("com.example.demo.model.mysql") .persistenceUnit("mysql") .build(); }
Secondary Entity Manager Factory
@Bean(name = "oracleEntityManagerFactory") public LocalContainerEntityManagerFactoryBean oracleEntityManagerFactory( EntityManagerFactoryBuilder builder, @Qualifier("oracleDataSource") DataSource oracleDataSource) { return builder.dataSource(oracleDataSource) .packages("com.example.demo.model.oracle") .persistenceUnit("oracle") .build(); }
我們使用@Qualifie注解,自動(dòng)將DataSource關(guān)聯(lián)到對(duì)應(yīng)的EntityManangerFactory中。
在這里我們可以分別配置實(shí)體類管理工廠所管理的packages,為了方便開(kāi)發(fā)和閱讀,分別將mysql和oracle關(guān)聯(lián)的實(shí)體類放在對(duì)應(yīng)的目錄下。
事務(wù)管理
我們?yōu)槊總€(gè)數(shù)據(jù)庫(kù)創(chuàng)建一個(gè)JPA事務(wù)管理器。
查看源碼我們可以發(fā)現(xiàn)JPA事務(wù)管理器需要EntityManangerFactory作為入?yún)?,所以利用上述定義的EntityMangerFactory分別生成對(duì)應(yīng)的JPA事物管理器。
源碼:
public JpaTransactionManager(EntityManagerFactory emf) { this(); this.entityManagerFactory = emf; this.afterPropertiesSet(); }
Primary transaction manager
@Primary @Bean(name = "mysqlTransactionManager") public PlatformTransactionManager mysqlTransactionManager(final @Qualifier("mysqlEntityManagerFactory") LocalContainerEntityManagerFactoryBean mysqlEntityManagerFactory) { return new JpaTransactionManager(mysqlEntityManagerFactory.getObject()); }
Secondary transaction manager
@Bean(name = "oracleTransactionManager") public PlatformTransactionManager oracleTransactionManager( final @Qualifier("oracleEntityManagerFactory") LocalContainerEntityManagerFactoryBean oracleEntityManagerFactory) { return new JpaTransactionManager(oracleEntityManagerFactory.getObject()); }
JPA Repository配置
由于我們使用了兩個(gè)不同的數(shù)據(jù)源,所以我們必須使用@EnableJpaRepositories注解為每個(gè)數(shù)據(jù)源提供特定的信息。
進(jìn)入該注解源碼,我們可以發(fā)現(xiàn)默認(rèn)值如下:
/** * Annotation to enable JPA repositories. Will scan the package of the annotated configuration class for Spring Data * repositories by default. * * @author Oliver Gierke * @author Thomas Darimont */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import(JpaRepositoriesRegistrar.class) public @interface EnableJpaRepositories { /** * Base packages to scan for annotated components. {@link #value()} is an alias for (and mutually exclusive with) this * attribute. Use {@link #basePackageClasses()} for a type-safe alternative to String-based package names. */ String[] basePackages() default {}; /** * Configures the name of the {@link EntityManagerFactory} bean definition to be used to create repositories * discovered through this annotation. Defaults to {@code entityManagerFactory}. * * @return */ String entityManagerFactoryRef() default "entityManagerFactory"; /** * Configures the name of the {@link PlatformTransactionManager} bean definition to be used to create repositories * discovered through this annotation. Defaults to {@code transactionManager}. * * @return */ String transactionManagerRef() default "transactionManager"; }
這里僅列了一些我們關(guān)心的方法。
從源碼我中我們可以看見(jiàn),
- basePackages: 使用此字段設(shè)置Repository的基本包,必須指向軟件包中repository所在目錄。
- entityManagerFactoryRef:使用此字段引用默認(rèn)或自定義的Entity Manager Factory, 這里通過(guò)Bean的名稱進(jìn)行指定, 默認(rèn)Bean為entityManagerFactory。
- transactionManagerRef:使用此字段引用默認(rèn)或自定義的事務(wù)管理器,這里通過(guò)Bean的名稱進(jìn)行指定,默認(rèn)Bean為transactionManager。
通過(guò)上面的內(nèi)容,我們?yōu)閮蓚€(gè)不同的數(shù)據(jù)源分別定義了不同的名稱,所以我們需要在這里分別將其注入容器中。
Primary
@Configuration @EnableTransactionManagement @EnableJpaRepositories(basePackages = {"com.example.demo.repository.mysql"}, entityManagerFactoryRef = "mysqlEntityManagerFactory", transactionManagerRef = "mysqlTransactionManager") public class MysqlDataSourceConfiguration { ... }
secondary
@Configuration @EnableTransactionManagement @EnableJpaRepositories(basePackages = "com.example.demo.repository.oracle", entityManagerFactoryRef = "oracleEntityManagerFactory", transactionManagerRef = "oracleTransactionManager") public class OracleDataSourceConfiguration { ... }
完整的配置文件
primary
@Configuration @EnableTransactionManagement @EnableJpaRepositories(basePackages = {"com.example.demo.repository.mysql"}, entityManagerFactoryRef = "mysqlEntityManagerFactory", transactionManagerRef = "mysqlTransactionManager") public class MysqlDataSourceConfiguration { @Primary @Bean(name = "mysqlDataSourceProperties") @ConfigurationProperties("spring.datasource") public DataSourceProperties dataSourceProperties() { return new DataSourceProperties(); } @Primary @Bean(name = "mysqlDataSource") @ConfigurationProperties("spring.datasource.configuration") public DataSource dataSource (@Qualifier("mysqlDataSourceProperties") DataSourceProperties mysqlDataSourceProperties) { return mysqlDataSourceProperties.initializeDataSourceBuilder() .type(HikariDataSource.class) .build(); } @Primary @Bean(name = "mysqlEntityManagerFactory") public LocalContainerEntityManagerFactoryBean entityManagerFactory( EntityManagerFactoryBuilder builder, @Qualifier("mysqlDataSource") DataSource mysqlDataSource) { return builder.dataSource(mysqlDataSource) .packages("com.example.demo.model.mysql") .persistenceUnit("mysql") .build(); } @Primary @Bean(name = "mysqlTransactionManager") public PlatformTransactionManager transactionManager(final @Qualifier("mysqlEntityManagerFactory") LocalContainerEntityManagerFactoryBean mysqlEntityManagerFactory) { return new JpaTransactionManager(mysqlEntityManagerFactory.getObject()); } }
secondary
@Configuration @EnableTransactionManagement @EnableJpaRepositories(basePackages = "com.example.demo.repository.oracle", entityManagerFactoryRef = "oracleEntityManagerFactory", transactionManagerRef = "oracleTransactionManager") public class OracleDataSourceConfiguration { @Bean(name = "oracleDataSourceProperties") @ConfigurationProperties("spring.second.datasource") public DataSourceProperties dataSourceProperties() { return new DataSourceProperties(); } @Bean @ConfigurationProperties("spring.second.datasource.configuration") public DataSource oracleDataSource(@Qualifier("oracleDataSourceProperties") DataSourceProperties oracleDataSourceProperties) { return oracleDataSourceProperties.initializeDataSourceBuilder() .type(HikariDataSource.class) .build(); } @Bean(name = "oracleEntityManagerFactory") public LocalContainerEntityManagerFactoryBean oracleEntityManagerFactory( EntityManagerFactoryBuilder builder, @Qualifier("oracleDataSource") DataSource oracleDataSource) { return builder.dataSource(oracleDataSource) .packages("com.example.demo.model.oracle") .persistenceUnit("oracle") .build(); } @Bean public PlatformTransactionManager oracleTransactionManager( final @Qualifier("oracleEntityManagerFactory") LocalContainerEntityManagerFactoryBean oracleEntityManagerFactory) { return new JpaTransactionManager(oracleEntityManagerFactory.getObject()); } }
總結(jié)
當(dāng)僅有一個(gè)數(shù)據(jù)源時(shí),Spring Boot會(huì)默認(rèn)自動(dòng)配置好,但是如果使用多個(gè)數(shù)據(jù)源時(shí),需要進(jìn)行一些自定義的配置,以上便是全部的配置。
到此這篇關(guān)于SpringBoot多數(shù)據(jù)庫(kù)連接(mysql+oracle)的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)SpringBoot多數(shù)據(jù)庫(kù)連接內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- springboot+idea+maven 多模塊項(xiàng)目搭建的詳細(xì)過(guò)程(連接數(shù)據(jù)庫(kù)進(jìn)行測(cè)試)
- Springboot2.0配置JPA多數(shù)據(jù)源連接兩個(gè)mysql數(shù)據(jù)庫(kù)方式
- springboot如何連接兩個(gè)數(shù)據(jù)庫(kù)(多個(gè))
- SpringBoot配置連接兩個(gè)或多個(gè)數(shù)據(jù)庫(kù)的實(shí)現(xiàn)
- SpringBoot配置連接兩個(gè)或多個(gè)數(shù)據(jù)庫(kù)的常用方法
- springboot項(xiàng)目配置多數(shù)據(jù)庫(kù)連接的示例詳解
- SpringBoot配置多個(gè)數(shù)據(jù)源超簡(jiǎn)單步驟(連接多個(gè)數(shù)據(jù)庫(kù))
- springboot項(xiàng)目連接多種數(shù)據(jù)庫(kù)該如何操作詳析
相關(guān)文章
使用Mybatis實(shí)現(xiàn)分頁(yè)效果示例
大家好,本篇文章主要講的是使用Mybatis實(shí)現(xiàn)分頁(yè)效果示例,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12springboot aspect通過(guò)@annotation進(jìn)行攔截的實(shí)例代碼詳解
這篇文章主要介紹了springboot aspect通過(guò)@annotation進(jìn)行攔截的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08Jmeter如何獲取jtl文件中所有的請(qǐng)求報(bào)文詳解
JMeter的可以創(chuàng)建一個(gè)包含測(cè)試運(yùn)行結(jié)果的文本文件,這些通常稱為JTL文件,因?yàn)檫@是默認(rèn)擴(kuò)展名,但可以使用任何擴(kuò)展名,這篇文章主要給大家介紹了關(guān)于Jmeter如何獲取jtl文件中所有的請(qǐng)求報(bào)文的相關(guān)資料,需要的朋友可以參考下2021-09-09mybatis多個(gè)plugins的執(zhí)行順序解析
這篇文章主要介紹了mybatis多個(gè)plugins的執(zhí)行順序解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09Springboot使用RestTemplate調(diào)用第三方接口的操作代碼
這篇文章主要介紹了Springboot使用RestTemplate調(diào)用第三方接口,我只演示了最常使用的請(qǐng)求方式get、post的簡(jiǎn)單使用方法,當(dāng)然RestTemplate的功能還有很多,感興趣的朋友可以參考RestTemplate源碼2022-12-12Java?Servlet實(shí)現(xiàn)表白墻的代碼實(shí)例
最近用Servlet做了個(gè)小項(xiàng)目,分享給大家,下面這篇文章主要給大家介紹了關(guān)于Java?Servlet實(shí)現(xiàn)表白墻的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02