Spring Boot中的主/辅助故障转移DataSource

Mat*_*t H 13 spring spring-boot

我有一个Spring Boot应用程序,需要有一个主要和辅助数据源.当有连接问题时,我需要实现一些关于如何重新连接的逻辑.由于Spring为您提供连接,我似乎无法告诉它在出现问题时重新连接.

我知道如何制作2个数据源,但是当它使用哪一个时,哪里是处理逻辑的最佳位置.逻辑需要以这种方式工作:

  1. 连接到主要
  2. 如果存在连接问题,则资源不可用或发生连接超时,请尝试重新连接到主服务器.
  3. 如果主节点无法连接,请尝试连接到辅助节点
  4. 如果辅助节点无法连接,请继续重试步骤2和3,持续X分钟.

在Spring Service中处理这个问题是否最好/可能?我应该有一个不同的服务,只处理这个逻辑,我的其他服务使用它吗?不连接到DB的"弹簧方式"并使用"普通的旧Java方式"会更好吗?

以下是我所拥有的服务仅连接到主服务器的示例.

DatasourcesConfig

package com.helloworld.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import oracle.jdbc.pool.OracleDataSource;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;
import java.sql.SQLException;

@Configuration
public class DatasourcesConfig {

    @Primary
    @Bean(name = "primaryDataSource")
    DataSource primaryDataSource() throws SQLException {

        OracleDataSource dataSource = new OracleDataSource();

        dataSource.setUser("user");
        dataSource.setPassword("pass");
        dataSource.setURL("jdbc:oracle:thin:@(...primary connection...)");

        return dataSource;
    }

      @Bean(name = "secondaryDataSource")
      DataSource secondaryDataSource() throws SQLException {

          OracleDataSource dataSource = new OracleDataSource();

          dataSource.setUser("user");
          dataSource.setPassword("pass");
          dataSource.setURL("jdbc:oracle:thin:@(...secondary connection...)");

          return dataSource;
      }

    @Bean(name = "jdbcPrimary")
    @Autowired
    public JdbcTemplate primaryJdbcTemplate(@Qualifier("primaryDataSource") DataSource ds) {
        return new JdbcTemplate(ds);
    }

    @Bean(name = "jdbcSecondary")
    @Autowired
    public JdbcTemplate secondaryJdbcTemplate(@Qualifier("secondaryDataSource") DataSource ds) {
        return new JdbcTemplate(ds);
    }

}
Run Code Online (Sandbox Code Playgroud)

ExampleService

package com.helloworld.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

@Service
public class ExampleService {

    @Autowired
    @Qualifier("jdbcPrimary")
    private JdbcTemplate jdbcTemplatePrimary;

    @Autowired
    @Qualifier("jdbcSecondary")
    private JdbcTemplate jdbcTemplateSecondary;

    public SampleDTO getData(String a, String b){

        final String sql = "select a, b from TABLE_A where a=? and b=?";

        // Only checking Primary
        return jdbcTemplatePrimary.queryForObject(sql,
                new Object[]{a,b},
                new SampleRowMapper());

        // Is this the best place to catch exceptions and connect to Secondary?

    }

}
Run Code Online (Sandbox Code Playgroud)

SampleRowMapperSampleDTO类已经被排除在外,因为他们是非常基本的.

Joe*_*ick 7

我能够使用DZone的这篇文章实现这种机制:https://dzone.com/articles/using-ha-jdbc-with-spring-boot使用输入链接描述这里

HA-JDBC是可配置的,并且具有多种不同的故障转移策略.

在我们的例子中,我们建立了与两个不同数据库的连接,我们的主数据库备份到辅助数据库,因此可能不是最新的.

我们将此数据库用作只读,因此无需担心事务,因此请按以下方式进行设置:

  1. 平衡器工厂:简单 - 它将始终尝试主要,除非它不可用.
  2. 主数据库的权重设置为2,辅助设置的权重设置为1.将平衡器工厂设置为"简单"时,应该强制驱动程序转到主数据库,除非我们遇到问题.
  3. 默认同步策略:简单(我们不需要担心这个,因为它是只读的.
  4. 数据库元数据缓存工厂:简单
  5. 州经理工厂:简单

我无法在此时获得密码混淆,但有一天会重新审视.

我最初也遇到了登录问题,但我发现我确实需要在ha-jdbc驱动程序上使用用户名/密码.

上面的例子是用Groovy编写的,而不是Java.