SpringBoot多数据库连接(mysql+oracle)的实现
出于业务需求,有时我们需要在spring boot web应⽤程序中配置多个数据源并连接到多个数据库。
使⽤过Spring Boot框架的⼩伙伴们,想必都发现了Spring Boot对JPA提供了⾮常好的⽀持,在开发过程中可以很简洁的代码轻松访问数据库,获取我们想要的数据。
因此在这⾥,使⽤Spring Boot和JPA配置多个数据源的场景。
项⽬配置
在本⽂中,主要使⽤两个不同的数据库,分别为:
mysql(springboot)【primary,优先搜寻该数据库】:mysql数据库,包含User的信息
oracle(springboot): oracle数据库,包含Country信息
项⽬依赖
为了⽀持Mysql和Oracle数据库,我们必须要在l⽂件中添加相应的依赖。
<dependencies>
<dependency>
<groupId&acle</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类和Reposit
ory映射到两个不同的
包中。
## jdbc-primary
jdbc连接oraclespring.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.sql.jdbc.Driver
## jdbc-second
spring.second.datasource.url=jdbc:oracle:thin:@localhost:
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
数据源配置
需要注意的是,在配置多个数据源期间,必须将其中⼀个数据源标记为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")
public DataSourceProperties dataSourceProperties() {
return new DataSourceProperties();
}
@Primary
@Bean(name = "mysqlDataSource")
@ConfigurationProperties("figuration")
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.figuration")
public DataSource oracleDataSource(@Qualifier("oracleDataSourceProperties") DataSourceProperties oracleDataSourceProperties) {
return oracleDataSourceProperties.initializeDataSourceBuilder()
.type(HikariDataSource.class)
.build();
}
我们使⽤@Qualifier注解,⾃动关联指定的DataSourceProperties.
定义实体类管理⼯⼚的Bean
上⾯说了,应⽤程序使⽤Spring Data JPA的repository接⼝将我们从实体管理器(Entity Manager)中抽象出来,从⽽进⾏数据的访问。这⾥,我们使⽤jpa.LocalContainerEntityManagerFactoryBean这个Bean来创建EM实例,后⾯利⽤这个EM实例与JPA entities进⾏交互。
由于我们这⾥有两个数据源,所以我要为每个数据源单独创建⼀个EntityManagerFactory。
Primary Entity Manager Factory
@Primary
@Bean(name = "mysqlEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
EntityManagerFactoryBuilder builder, @Qualifier("mysqlDataSource") DataSource mysqlDataSource) {
return builder.dataSource(mysqlDataSource)
.packages("sql")
.
persistenceUnit("mysql")
.build();
}
Secondary Entity Manager Factory
@Bean(name = "oracleEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean oracleEntityManagerFactory(
EntityManagerFactoryBuilder builder, @Qualifier("oracleDataSource") DataSource oracleDataSource) {
return builder.dataSource(oracleDataSource)
.packages("acle")
.persistenceUnit("oracle")
.build();
}
我们使⽤@Qualifie注解,⾃动将DataSource关联到对应的EntityManangerFactory中。
在这⾥我们可以分别配置实体类管理⼯⼚所管理的packages,为了⽅便开发和阅读,分别将mysql和oracle关联的实体类放在对应的⽬录下。
事务管理
我们为每个数据库创建⼀个JPA事务管理器。
查看源码我们可以发现JPA事务管理器需要EntityManangerFactory作为⼊参,所以利⽤上述定义的EntityMangerFactory分别⽣成对应的JPA事物管理器。
源码:
public JpaTransactionManager(EntityManagerFactory emf) {
this();
this.afterPropertiesSet();
}
Primary transaction manager
@Primary
@Bean(name = "mysqlTransactionManager")
public PlatformTransactionManager mysqlTransactionManager(final @Qualifier("mysqlEntityManagerFactory")
LocalContainerEntityManagerFactoryBean mysqlEntityManagerFactory) {
return new Object());
}
Secondary transaction manager
@Bean(name = "oracleTransactionManager")
public PlatformTransactionManager oracleTransactionManager(
final @Qualifier("oracleEntityManagerFactory")
LocalContainerEntityManagerFactoryBean oracleEntityManagerFactory) {
return new Object());
}
JPA Repository配置
由于我们使⽤了两个不同的数据源,所以我们必须使⽤@EnableJpaRepositories注解为每个数据源提供特定的信息。
进⼊该注解源码,我们可以发现默认值如下:
/**
* 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";
}
这⾥仅列了⼀些我们关⼼的⽅法。
从源码我中我们可以看见,
basePackages: 使⽤此字段设置Repository的基本包,必须指向软件包中repository所在⽬录。
entityManagerFactoryRef:使⽤此字段引⽤默认或⾃定义的Entity Manager Factory, 这⾥通过Bean的名称进⾏指定,默认Bean为entityManagerFactory。
transactionManagerRef:使⽤此字段引⽤默认或⾃定义的事务管理器,这⾥通过Bean的名称进⾏指定,默认Bean为transactionManager。
通过上⾯的内容,我们为两个不同的数据源分别定义了不同的名称,所以我们需要在这⾥分别将其注⼊容器中。
Primary
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = {"sql"},
entityManagerFactoryRef = "mysqlEntityManagerFactory", transactionManagerRef = "mysqlTransactionManager")
public class MysqlDataSourceConfiguration {
...
}
secondary
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "acle",
entityManagerFactoryRef = "oracleEntityManagerFactory", transactionManagerRef = "oracleTransactionManager")
public class OracleDataSourceConfiguration {
...
}
完整的配置⽂件
primary
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = {"sql"},
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("figuration")
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("sql")
.persistenceUnit("mysql")
.build();
}
@Primary
@Bean(name = "mysqlTransactionManager")
public PlatformTransactionManager transactionManager(final @Qualifier("mysqlEntityManagerFactory")
LocalContainerEntityManagerFactoryBean mysqlEntityManagerFactory) {
return new Object());
}
}
secondary
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "acle",
entityManagerFactoryRef = "oracleEntityManagerFactory", transactionManagerRef = "oracleTransactionManager")
public class OracleDataSourceConfiguration {
@Bean(name = "oracleDataSourceProperties")
@ConfigurationProperties("spring.second.datasource")
public DataSourceProperties dataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@ConfigurationProperties("spring.figuration")
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("acle")
.persistenceUnit("oracle")
.build();
}
@Bean
public PlatformTransactionManager oracleTransactionManager(
final @Qualifier("oracleEntityManagerFactory")
LocalContainerEntityManagerFactoryBean oracleEntityManagerFactory) {
return new Object());
}
}
总结
当仅有⼀个数据源时,Spring Boot会默认⾃动配置好,但是如果使⽤多个数据源时,需要进⾏⼀些⾃定义的配置,以上便是全部的配置。
到此这篇关于SpringBoot多数据库连接(mysql+oracle)的实现的⽂章就介绍到这了,更多相关SpringBoot多数据库连接内容请搜
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论