如何在单个Boot应用中配置多数据库

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在单个Boot应用中配置多数据库相关的知识,希望对你有一定的参考价值。

为什么需要多数据库?
默认情况下,Spring Boot使用的是单数据库配置(通过spring.datasource.*配置具体数据库连接信息)。
对于绝大多数Spring Boot应用,这是符合其使用场景的,因为Spring Boot提倡的是微服务理念,每个应用对应一个单独的业务领域。但在某些特殊情况下,一个应用对应多个数据库又是无法避免的,例如实施数据库分库后原本单个数据库变为多个数据库。本文就结合实际代码介绍如何在单个Boot应用中配置多数据库,以及与之相关的Druid,jOOQ,Flyway等数据服务框架的配置改造。
配置示例

DB1,DB2: 两个示例数据库
ServiceA, ServiceB: 分别使用DB1和DB2的服务类
连接池Druid
Druid是阿里巴巴开源的数据库连接池,提供了强大的监控支持,号称Java语言中最好的连接池。
创建两个配置类分别注册对应DB1和DB2的DataSource Bean和TransactionManager Bean。以DB1为例:
Tip: 可以把其中一个配置类中注册的DataSource Bean和DataSourceTransactionManager Bean加上@Primary注解,作为默认装配实例。
// DB1
@Configuration
public class Db1Config

@Bean(initMethod = "init", destroyMethod = "close")
@ConfigurationProperties(prefix = "db.db1")
public DataSource dataSource1()
return new DruidDataSource();


@Bean
public DataSourceTransactionManager transactionManager1()
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource1());
return transactionManager;



application.conf中的配置:
# DB1
db.db1.url=jdbc:mysql://127.0.0.1:3306/db1?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true
db.db1.username=root
db.db1.password=

ORM框架jOOQ
jOOQ是一个开源ORM框架,最大特点是提供类型安全的流式API,支持代码生成。
参照Boot自带的JooqAutoConfiguration,不难写出如下配置类:
@Configuration
public class JooqConfig

// DB1
@Bean
public DataSourceConnectionProvider dataSourceConnectionProvider1(
@Qualifier("dataSource1") DataSource dataSource1)
return new DataSourceConnectionProvider(
new TransactionAwareDataSourceProxy(dataSource1));


@Bean
public SpringTransactionProvider transactionProvider1(
@Qualifier("transactionManager1") DataSourceTransactionManager txManager1)
return new SpringTransactionProvider(txManager1);


// DB2
// ...

@Configuration
public static class DslContextConfig

@Autowired(required = false)
private RecordMapperProvider recordMapperProvider;

@Autowired(required = false)
private Settings settings;

@Autowired(required = false)
private RecordListenerProvider[] recordListenerProviders;

@Autowired
private ExecuteListenerProvider[] executeListenerProviders;

@Autowired(required = false)
private VisitListenerProvider[] visitListenerProviders;

// DSLContext for DB1
@Bean
public DefaultDSLContext dslContext1(@Qualifier("dataSourceConnectionProvider1") DataSourceConnectionProvider connectionProvider1,
@Qualifier("transactionProvider1") SpringTransactionProvider transactionProvider1)
return new DefaultDSLContext(configuration(connectionProvider1, transactionProvider1));


// DSLContext for DB2
// ...

private DefaultConfiguration configuration(ConnectionProvider connectionProvider, TransactionProvider transactionProvider)
DefaultConfiguration configuration = new DefaultConfiguration();
configuration.setSQLDialect(SQLDialect.MYSQL);
configuration.set(connectionProvider);
configuration.set(transactionProvider);
if (this.recordMapperProvider != null)
configuration.set(this.recordMapperProvider);

if (this.settings != null)
configuration.set(this.settings);

configuration.set(this.recordListenerProviders);
configuration.set(this.executeListenerProviders);
configuration.set(this.visitListenerProviders);
return configuration;




服务类
配置好DataSource,TransacationManager和DSLContext之后,服务类的配置就比较简单了,直接引用即可。注意由于存在多套Beans,需要通过@Qualifier注解指定装配实例。
@Transactional("TransactionManager1")//每个事务指定 tx
public class ServiceA

@Autowired
@Qualifier("dslContext1")
protected DSLContext dsl;


数据库迁移框架Flyway
Flyway是一个轻量级的开源数据库迁移框架,使用非常广泛。
参照Boot自带的FlywayAutoConfiguration,同样可以写出如下配置类:
@Configuration
public class FlywayConfig

@Bean(initMethod = "migrate")
@ConfigurationProperties(prefix = "fw.db1")
public Flyway flyway(@Qualifier("dataSource1") DataSource dataSource1)
Flyway clinic = new Flyway();
clinic.setDataSource(dataSource1);
return clinic;


// DB2
// ...

/**
* @see FlywayAutoConfiguration
*/
@Bean
@ConfigurationPropertiesBinding
public StringOrNumberToMigrationVersionConverter stringOrNumberMigrationVersionConverter()
return new StringOrNumberToMigrationVersionConverter();


/**
* Convert a String or Number to a @link MigrationVersion.
* @see FlywayAutoConfiguration
*/
private static class StringOrNumberToMigrationVersionConverter
implements GenericConverter

private static final Set<ConvertiblePair> CONVERTIBLE_TYPES;

static
Set<ConvertiblePair> types = new HashSet<ConvertiblePair>(2);
types.add(new ConvertiblePair(String.class, MigrationVersion.class));
types.add(new ConvertiblePair(Number.class, MigrationVersion.class));
CONVERTIBLE_TYPES = Collections.unmodifiableSet(types);


@Override
public Set<ConvertiblePair> getConvertibleTypes()
return CONVERTIBLE_TYPES;


@Override
public Object convert(Object source, TypeDescriptor sourceType,
TypeDescriptor targetType)
String value = ObjectUtils.nullSafeToString(source);
return MigrationVersion.fromVersion(value);





application.conf中的配置:
# DB1
fw.db1.enabled=true
参考技术A --在WEB.config配置下面的节点,connectionstring写的是连接数据库的字符串datasource是填写的数据库,initialcatalog是连接的数据库名称,user id是连接数据的账户名,password是账户的密码
<connectionStrings>
<add name="connstring" connectionString="Data Source=.\HH;Initial Catalog=stu;User ID=sa;Password=123;"/>
</connectionStrings>
--在web应用层获取这段数据库连接字符串的语句是
ConfigurationManager.ConnectionStrings["connstring"].ToString()

如何在 Spring Boot 应用程序中使用 hikari 配置自动重新连接?

【中文标题】如何在 Spring Boot 应用程序中使用 hikari 配置自动重新连接?【英文标题】:How to configure auto reconnection with hikari in SpringBoot application? 【发布时间】:2019-11-28 01:31:11 【问题描述】:

我们使用的是 SpringBoot 2.1.x 版本,所以 Hikari 是默认的 DataSource 实现。但是,我不确定如何配置 Hikari 设置以在数据库维护/重启或网络连接问题后自动重新连接到我们的 Oracle 数据库。

我们有以下 hikari 设置,但它似乎没有帮助。

account.datasource.url: jdbc:oracle:thin:@myserver:1521:DEV
account.datasource.username: user
account.datasource.password: xxxx
account.datasource.driverClassName: oracle.jdbc.driver.OracleDriver

account.datasource.hikari.connection-timeout: 30000
account.datasource.hikari.maximum-pool-size: 3
account.datasource.hikari.idle-timeout: 60000
account.datasource.hikari.max-lifetime: 1800000
account.datasource.hikari.minimum-idle: 2

与数据库的网络连接恢复后重新连接失败。

获取JDBC连接失败;嵌套异常是 java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30033ms.

任何其他 account.datasource.hikari.xxxxx 将有助于自动重新连接到数据库?

【问题讨论】:

【参考方案1】:

来自 HikariCP docs:

连接测试查询

如果您的驱动程序支持 JDBC4,我们强烈 建议不要设置此属性。这适用于“传统”驱动程序 不支持 JDBC4 Connection.isValid() API。这是查询 这将在从给您提供连接之前执行 验证与数据库的连接是否仍然存在的池 活。再次尝试在没有此属性的情况下运行池 HikariCP 如果您的驱动程序不兼容 JDBC4 将记录一个错误以让您 知道。默认值:无

所以我建议验证您的 JDBC 驱动程序实际上是否符合 JDBC4。如果不是 - 设置上述属性。

【讨论】:

2019-07-19 08:26:24.158 --- com.zaxxer.hikari.HikariDataSource: HikariPool-1 - 开始... 2019-07-19 08:26:24.161 --- com.zaxxer.hikari.util.DriverDataSource:未找到已注册的驱动程序 driverClassName=oracle.jdbc.driver.OracleDriver,正在尝试直接实例化。 2019-07-19 08:26:25.375 --- com.zaxxer.hikari.pool.PoolBase: HikariPool-1 - 驱动程序不支持获取/设置连接的网络超时。 (oracle.jdbc.driver.T4CConnection.getNetworkTimeout()I) 2019-07-19 08:26:25.430 --- com.zaxxer.hikari.HikariDataSource: HikariPool-1 - 启动完成。 谢谢。我在日志中没有看到任何错误,所以 JDBC 4 投诉,对吧? 我们发现了重新连接的问题。上述设置实际上负责自动重新连接。但是,我们内部存在网络服务器问题,导致了包括重新连接在内的各种问题。干得好 Hikari 数据源。

以上是关于如何在单个Boot应用中配置多数据库的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 1 数据库多数据库用户

如何配置多模块spring应用

spring boot动态数据源配置如何配置

Spring Boot 多环境配置

spring boot +mybatis+druid 多数据源配置

Spring Boot 2.X:MyBatis 多数据源配置