SpringBoot多数据库毗邻(mysql+oracle)

admin 3个月前 (07-24) 科技 38 0
出于营业需求,有时我们需要在spring boot web应用程序中设置多个数据源并毗邻到多个数据库。 使用过Spring Boot框架的小伙伴们,想必都发现了Spring Boot对JPA提供了非常好的支持,在开发过程中可以很简练的代码轻松接见数据库,获取我们想要的数据。 因此在这里,使用Spring Boot和JPA设置多个数据源的场景。

项目设置

在本文中,主要使用两个差别的数据库,划分为:
  • 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-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会默认自动设置好,然则若是使用多个数据源时,需要举行一些自界说的设置,以上即是所有的设置。 总体感受并不是稀奇庞大,耐心明白下,照样很容易明白的。 若有错漏之处,还望列位大佬们指正。    作者:吴家二少 博客地址:https://www.cnblogs.com/cloudman-open/ 本文迎接转载,但未经作者赞成必须保留此段声明,且在文章页面显著位置给出原文毗邻 

,

Allbet客户端下载

欢迎进入Allbet客户端下载(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。

dafa888体育声明:该文看法仅代表作者自己,与本平台无关。转载请注明:SpringBoot多数据库毗邻(mysql+oracle)

网友评论

  • (*)

最新评论

文章归档

站点信息

  • 文章总数:796
  • 页面总数:0
  • 分类总数:8
  • 标签总数:1392
  • 评论总数:427
  • 浏览总数:32073