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文件中添加相应的依赖。

<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会默认自动配置好,但是如果使用多个数据源时,需要进行一些自定义的配置,以上便是全部的配置。

到此这篇关于SpringBoot多数据库连接(mysql+oracle)的实现的文章就介绍到这了,更多相关SpringBoot多数据库连接内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 解决Springboot项目启动后自动创建多表关联的数据库与表的方案

    熬夜写完,尚有不足,但仍在努力学习与总结中,而您的点赞与关注,是对我最大的鼓励! 在一些本地化项目开发当中,存在这样一种需求,即开发完成的项目,在第一次部署启动时,需能自行构建系统需要的数据库及其对应的数据库表. 若要解决这类需求,其实现在已有不少开源框架都能实现自动生成数据库表,如mybatis plus.spring JPA等,但您是否有想过,若要自行构建一套更为复杂的表结构时,这种开源框架是否也能满足呢,若满足不了话,又该如何才能实现呢? 我在前面写过一篇 Activiti工作流学习笔记(

  • 通过Spring Boot配置动态数据源访问多个数据库的实现代码

    之前写过一篇博客<Spring+Mybatis+Mysql搭建分布式数据库访问框架>描述如何通过Spring+Mybatis配置动态数据源访问多个数据库.但是之前的方案有一些限制(原博客中也描述了):只适用于数据库数量不多且固定的情况.针对数据库动态增加的情况无能为力. 下面讲的方案能支持数据库动态增删,数量不限. 数据库环境准备 下面一Mysql为例,先在本地建3个数据库用于测试.需要说明的是本方案不限数据库数量,支持不同的数据库部署在不同的服务器上.如图所示db_project_001.d

  • springboot+idea+maven 多模块项目搭建的详细过程(连接数据库进行测试)

    创建之前项目之前 记得改一下 maven  提高下载Pom速度 记得 setting 中要改 maven  改成 阿里云的.具体方法 网上查第一步 搭建parents 项目,为maven项目 ,不为springboot 项目 记得修改groupId 第二步 搭建多个子模块, honor-dao   honor-manager   honor-common记得创建 honor-manager 的时候 要把他的gruopId 改成com.honor.manager 这里爆红的原因是 因为 我做到后面

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

    出于业务需求,有时我们需要在spring boot web应用程序中配置多个数据源并连接到多个数据库. 使用过Spring Boot框架的小伙伴们,想必都发现了Spring Boot对JPA提供了非常好的支持,在开发过程中可以很简洁的代码轻松访问数据库,获取我们想要的数据. 因此在这里,使用Spring Boot和JPA配置多个数据源的场景. 项目配置 在本文中,主要使用两个不同的数据库,分别为: mysql(springboot)[primary,优先搜寻该数据库]:mysql数据库,包含Us

  • SpringBoot集成mybatis连接oracle的图文教程

    目录 一.背景 原始的连接数据库的步骤 二.整合过程 springboot集成mybatis连接oracle数据库的过程 个人感悟 一.背景 在实际开发过程中是离不开数据库的,如果不使用任何框架,那么连接数据库的代码会散落在项目的各个地方,且容易出现各种连接数据库问题. 原始的连接数据库的步骤 1.加载驱动(什么数据库,就记载什么驱动) 2.获取连接 3.编写sql 4.创建statement 5.执行sql语句并处理结果 6.自下而上一次关闭连接(容易出现异常) 在实际开发中,操作数据库还是很

  • springboot druid数据库连接池连接失败后一直重连的解决方法

    目录 druid 重连原因 errorCount 错误次数 总结 在使用个人阿里云测试机,在查询实时输出日志时,看到数据库连接失败后,服务器一直在重连服务器.开始以为是遭受重复攻击,后面把服务重启后,就没有出现一直重连的情况.看以下输出日志: 2022-02-09 11:04:58.896 ERROR 16876 --- [eate-1550991149] com.alibaba.druid.pool.DruidDataSource   : create connection SQLExcept

  • SpringBoot Mybatis批量插入Oracle数据库数据

    目录 前端数据 数据表结构 后端Controller: mapper xml 前端数据 有如下需求,前端提交一个对象cabinData,保存到数据表中,对象结构如下:  {      "shipId":"424",      "shipName":"大唐2号",      "ballastCabinData":["艏尖舱","双层底1左","双层底1右&qu

  • mysql oracle和sqlserver分页查询实例解析

    最近简单的对oracle,mysql,sqlserver2005的数据分页查询作了研究,把各自的查询的语句贴出来供大家学习..... (一).mysql的分页查询 mysql的分页查询是最简单的,借助关键字limit即可实现查询,查询语句通式: selecto.*from(sql)o limit firstIndex,pageSize 如下面的截图,每页显示的记录数为20: 查询(1-20)这20条记录 查询(21-40)这20条记录 mysql的分页查询就这么简单...... (二).sqls

  • PHP数据库连接mysql与mysqli对比分析

    一.mysql与mysqli的概念相关 1.mysql与mysqli都是php方面的函数集,与mysql数据库关联不大. 2.在php5版本之前,一般是用php的mysql函数去驱动mysql数据库的,比如mysql_query()的函数,属于面向过程3.在php5版本以后,增加了mysqli的函数功能,某种意义上讲,它是mysql系统函数的增强版,更稳定更高效更安全,与mysql_query()对应的有mysqli_query(),属于面向对象,用对象的方式操作驱动mysql数据库 二.mys

  • springboot基于Mybatis mysql实现读写分离

    近日工作任务较轻,有空学习学习技术,遂来研究如果实现读写分离.这里用博客记录下过程,一方面可备日后查看,同时也能分享给大家(网上的资料真的大都是抄来抄去,,还不带格式的,看的真心难受). 完整代码:https://github.com/FleyX/demo-project/tree/master/dxfl 1.背景 一个项目中数据库最基础同时也是最主流的是单机数据库,读写都在一个库中.当用户逐渐增多,单机数据库无法满足性能要求时,就会进行读写分离改造(适用于读多写少),写操作一个库,读操作多个库

  • Springboot项目实现Mysql多数据源切换的完整实例

    一.分析AbstractRoutingDataSource抽象类源码 关注import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource以下变量 @Nullable private Map<Object, Object> targetDataSources; // 目标数据源 @Nullable private Object defaultTargetDataSource; // 默认目标数据源 @Null

  • SpringBoot+Mybatis-Plus实现mysql读写分离方案的示例代码

    1. 引入mybatis-plus相关包,pom.xml文件 2. 配置文件application.property增加多库配置 mysql 数据源配置 spring.datasource.primary.jdbc-url=jdbc:mysql://xx.xx.xx.xx:3306/portal?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=

  • Springboot整合camunda+mysql的集成流程分析

    一.创建springboot工程 使用IDEA工具,选择File->New->Project,选择Spring Initialzr 输入springboot工程基本信息,本示例命名为"camunda-demo1", jdk版本选择8 在选择springboot组件的时候,需要选择Spring Web.JDBC API.MySql Driver 这三个组件.点击下一步完成即可. 二.修改maven配置 2.1.修改springboot版本号 由于camunda版本与sprin

随机推荐