综合百科

怎么在SpringBoot中实现多数据库连接

怎么在Springboot中实现多数据库连接?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

主要使用两个不同的数据库,分别为:

  • mysql(springboot)【primary,优先搜寻该数据库】:mysql数据库,包含User的信息

  • oracle(springboot): oracle数据库, 包含Country信息

项目依赖

为了支持Mysql和Oracle数据库,我们必须要在pom.xml文件中添加相应的依赖。

<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>

包管理

为了方便代码的开发,我们将mysql和oracle分开放在两个不同的package下面,具体的包结构如下:

将不同的模型分开放入mysql和oracle包目录下,需要注意的是,mysql和oracle为两个不同的数据库,所以两个数据库中可能存在某个表名称一致的场景。该场景下,会优先匹配primary的数据库,如果该数据库down了,才会匹配另外一张表。所以,如果想要两张表都正常使用,建议使用不同的Entity名称。

数据库连接配置

我们在属性文件application.properties中分别配置两个单独的jdbc连接,将所有关联的Entity类和Repository映射到两个不同的包中。

##jdbc-primaryspring.datasource.url=jdbc:mysql://localhost:33306/springboot?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=falsespring.datasource.username=springbootspring.datasource.password=123456spring.ds_mysql.driverClassName=com.mysql.jdbc.Driver##jdbc-secondspring.second.datasource.url=jdbc:oracle:thin:@localhost:1909/xxx.xxx.comspring.second.datasource.userName=springbootspring.second.datasource.password=123456spring.second.datasource.driver-class-name=oracle.jdbc.OracleDriver##jpaspring.jpa.hibernate.ddl-auto=nonespring.jpa.show-sql=truespring.jpa.properties.hibernate.jdbc.time_zone=UTCspring.jpa.properties.hibernate.jdbc.fetch_size=500spring.jpa.properties.hibernate.jdbc.batch_size=100

数据源配置

需要注意的是,在配置多个数据源期间,必须将其中一个数据源标记为primary,否则Spring Boot会检测到多个类型的数据源,从而无法正常启动。

定义Data Source的Bean

想要创建Data Source,我们必须先实例化org.springframework.boot.autoconfigure.jdbc.DataSourceProperties类,加载application.properties文件中配置的数据库连接信息,并通过DataSourceProperties对象的初始化builder方法创建一个javax.sql.DataSource对象。

primary Data Source

@Primary@Bean(name="mysqlDataSourceProperties")@ConfigurationProperties("spring.datasource")publicDataSourcePropertiesdataSourceProperties(){returnnewDataSourceProperties();}@Primary@Bean(name="mysqlDataSource")@ConfigurationProperties("spring.datasource.configuration")publicDataSourcedataSource(@Qualifier("mysqlDataSourceProperties")DataSourcePropertiesmysqlDataSourceProperties){returnmysqlDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();}

Secondary Data Source

@Bean(name="oracleDataSourceProperties")@ConfigurationProperties("spring.second.datasource")publicDataSourcePropertiesdataSourceProperties(){returnnewDataSourceProperties();}@Bean@ConfigurationProperties("spring.second.datasource.configuration")publicDataSourceoracleDataSource(@Qualifier("oracleDataSourceProperties")DataSourcePropertiesoracleDataSourceProperties){returnoracleDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();}

我们使用@Qualifier注解,自动关联指定的DataSourceProperties.

定义实体类管理工厂的Bean

上面说了,应用程序使用Spring Data JPA的repository接口将我们从实体管理器(Entity Manager)中抽象出来,从而进行数据的访问。这里,我们使用org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean这个Bean来创建EM实例,后面利用这个EM实例与JPA entities进行交互。

由于我们这里有两个数据源,所以我要为每个数据源单独创建一个EntityManagerFactory。

Primary Entity Manager Factory

@Primary@Bean(name="mysqlEntityManagerFactory")publicLocalContainerEntityManagerFactoryBeanentityManagerFactory(EntityManagerFactoryBuilderbuilder,@Qualifier("mysqlDataSource")DataSourcemysqlDataSource){returnbuilder.dataSource(mysqlDataSource).packages("com.example.demo.model.mysql").persistenceUnit("mysql").build();}

Secondary Entity Manager Factory

@Bean(name="oracleEntityManagerFactory")publicLocalContainerEntityManagerFactoryBeanoracleEntityManagerFactory(EntityManagerFactoryBuilderbuilder,@Qualifier("oracleDataSource")DataSourceoracleDataSource){returnbuilder.dataSource(oracleDataSource).packages("com.example.demo.model.oracle").persistenceUnit("oracle").build();}

我们使用@Qualifie注解,自动将DataSource关联到对应的EntityManangerFactory中。
在这里我们可以分别配置实体类管理工厂所管理的packages,为了方便开发和阅读,分别将mysql和oracle关联的实体类放在对应的目录下。

事务管理

我们为每个数据库创建一个JPA事务管理器。
查看源码我们可以发现JPA事务管理器需要EntityManangerFactory作为入参,所以利用上述定义的EntityMangerFactory分别生成对应的JPA事物管理器。

源码:

publicJpaTransactionManager(EntityManagerFactoryemf){this();this.entityManagerFactory=emf;this.afterPropertiesSet();}

Primary transaction manager

@Primary@Bean(name="mysqlTransactionManager")publicPlatformTransactionManagermysqlTransactionManager(final@Qualifier("mysqlEntityManagerFactory")LocalContainerEntityManagerFactoryBeanmysqlEntityManagerFactory){returnnewJpaTransactionManager(mysqlEntityManagerFactory.getObject());}

Secondary transaction manager

@Bean(name="oracleTransactionManager")publicPlatformTransactionManageroracleTransactionManager(final@Qualifier("oracleEntityManagerFactory")LocalContainerEntityManagerFactoryBeanoracleEntityManagerFactory){returnnewJpaTransactionManager(oracleEntityManagerFactory.getObject());}

JPA Repository配置

由于我们使用了两个不同的数据源,所以我们必须使用@EnableJpaRepositories注解为每个数据源提供特定的信息。
进入该注解源码,我们可以发现默认值如下:

/***AnnotationtoenableJPArepositories.WillscanthepackageoftheannotatedconfigurationclassforSpringData*repositoriesbydefault.**@authorOliverGierke*@authorThomasDarimont*/@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@Import(JpaRepositoriesRegistrar.class)public@interfaceEnableJpaRepositories{/***Basepackagestoscanforannotatedcomponents.{@link#value()}isanaliasfor(andmutuallyexclusivewith)this*attribute.Use{@link#basePackageClasses()}foratype-safealternativetoString-basedpackagenames.*/String[]basePackages()default{};/***Configuresthenameofthe{@linkEntityManagerFactory}beandefinitiontobeusedtocreaterepositories*discoveredthroughthisannotation.Defaultsto{@codeentityManagerFactory}.**@return*/StringentityManagerFactoryRef()default"entityManagerFactory";/***Configuresthenameofthe{@linkPlatformTransactionManager}beandefinitiontobeusedtocreaterepositories*discoveredthroughthisannotation.Defaultsto{@codetransactionManager}.**@return*/StringtransactionManagerRef()default"transactionManager";}

这里仅列了一些我们关心的方法。

从源码我中我们可以看见,

  • basePackages: 使用此字段设置Repository的基本包,必须指向软件包中repository所在目录。

  • entityManagerFactoryRef:使用此字段引用默认或自定义的Entity Manager Factory, 这里通过Bean的名称进行指定, 默认Bean为entityManagerFactory。

  • transactionManagerRef:使用此字段引用默认或自定义的事务管理器,这里通过Bean的名称进行指定,默认Bean为transactionManager。

通过上面的内容,我们为两个不同的数据源分别定义了不同的名称,所以我们需要在这里分别将其注入容器中。

Primary

@Configuration@EnableTransactionManagement@EnableJpaRepositories(basePackages={"com.example.demo.repository.mysql"},entityManagerFactoryRef="mysqlEntityManagerFactory",transactionManagerRef="mysqlTransactionManager")publicclassMysqlDataSourceConfiguration{...}

secondary

@Configuration@EnableTransactionManagement@EnableJpaRepositories(basePackages="com.example.demo.repository.oracle",entityManagerFactoryRef="oracleEntityManagerFactory",transactionManagerRef="oracleTransactionManager")publicclassOracleDataSourceConfiguration{...}

完整的配置文件

primary

@Configuration@EnableTransactionManagement@EnableJpaRepositories(basePackages={"com.example.demo.repository.mysql"},entityManagerFactoryRef="mysqlEntityManagerFactory",transactionManagerRef="mysqlTransactionManager")publicclassMysqlDataSourceConfiguration{@Primary@Bean(name="mysqlDataSourceProperties")@ConfigurationProperties("spring.datasource")publicDataSourcePropertiesdataSourceProperties(){returnnewDataSourceProperties();}@Primary@Bean(name="mysqlDataSource")@ConfigurationProperties("spring.datasource.configuration")publicDataSourcedataSource(@Qualifier("mysqlDataSourceProperties")DataSourcePropertiesmysqlDataSourceProperties){returnmysqlDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();}@Primary@Bean(name="mysqlEntityManagerFactory")publicLocalContainerEntityManagerFactoryBeanentityManagerFactory(EntityManagerFactoryBuilderbuilder,@Qualifier("mysqlDataSource")DataSourcemysqlDataSource){returnbuilder.dataSource(mysqlDataSource).packages("com.example.demo.model.mysql").persistenceUnit("mysql").build();}@Primary@Bean(name="mysqlTransactionManager")publicPlatformTransactionManagertransactionManager(final@Qualifier("mysqlEntityManagerFactory")LocalContainerEntityManagerFactoryBeanmysqlEntityManagerFactory){returnnewJpaTransactionManager(mysqlEntityManagerFactory.getObject());}}

secondary

@Configuration@EnableTransactionManagement@EnableJpaRepositories(basePackages="com.example.demo.repository.oracle",entityManagerFactoryRef="oracleEntityManagerFactory",transactionManagerRef="oracleTransactionManager")publicclassOracleDataSourceConfiguration{@Bean(name="oracleDataSourceProperties")@ConfigurationProperties("spring.second.datasource")publicDataSourcePropertiesdataSourceProperties(){returnnewDataSourceProperties();}@Bean@ConfigurationProperties("spring.second.datasource.configuration")publicDataSourceoracleDataSource(@Qualifier("oracleDataSourceProperties")DataSourcePropertiesoracleDataSourceProperties){returnoracleDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();}@Bean(name="oracleEntityManagerFactory")publicLocalContainerEntityManagerFactoryBeanoracleEntityManagerFactory(EntityManagerFactoryBuilderbuilder,@Qualifier("oracleDataSource")DataSourceoracleDataSource){returnbuilder.dataSource(oracleDataSource).packages("com.example.demo.model.oracle").persistenceUnit("oracle").build();}@BeanpublicPlatformTransactionManageroracleTransactionManager(final@Qualifier("oracleEntityManagerFactory")LocalContainerEntityManagerFactoryBeanoracleEntityManagerFactory){returnnewJpaTransactionManager(oracleEntityManagerFactory.getObject());}}

关于怎么在SpringBoot中实现多数据库连接问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注亿速云行业资讯频道了解更多相关知识。