SpringBoot多数据库连接(mysql+oracle)的实现

网友投稿 267 2023-01-25

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数据库,我们必须要在pom.xml文件中添加相应的依赖。

com.oracle

ojdbc6

11.2.0.3.0

compile

mysql

mysql-connector-java

org.springframework.boot

spring-boot-starter-data-jpa

javax.persistence

javax.persistence-api

2.2

org.projectlombok

lombok

1.18.12

包管理

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

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

数据库连接配置

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

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

数据源配置

需要注意的是,在配置多个数据源期间,必须将其中一个数据源标记为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("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注解,自动关联指定的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")

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注解,自动将DataSource关联到对应的EntityManangerFactory中。

在这里我们可以分别配置实体类管理工厂所管理的packages,为了方便开发和阅读,分别将mysql和oracle关联的实体类放在对应的目录下。

事务管理

我们为每个数据库创建一个JPA事务管理器。

查看源码我们可以发现JPA事务管理器需要EntityManangerFactory作为入参,所以利用上述定义的EntityMangerFactory分别生成对应的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配置

由于我们使用了两个不同的数据源,所以我们必须使用@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 = {"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());

}

}

总结

当仅有一个数据源时,Spring Boot会默认自动配置好,但是如果使用多个数据源时,需要进行一些自定义的配置,以上便是全部的配置。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:SpringBoot多数据源配置详细教程(JdbcTemplate、mybatis)
下一篇:免费api管理软件(api文档软件)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~