【Spring】如何在单个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
关于事务
有经验的同学马上会问,多数据库下事务会不会有问题?需要改造成分布式事务吗?
只要为每个数据库创建独立的TransactionManager,就不会有问题,Spring会自动处理好事务的提交和回滚,就像单数据库一样。
至于分布式事务,大可不必,因为虽然有多个数据库,但仍然属于Local Transaction范畴。以后有时间我会再写篇文章展开阐述一下。
总结
由上可见,无论是基础的DataSource和TransactionManager,还是Spring之外的第三方框架,在Boot中基本都可以找到相应的AutoConfiguration配置类。参照这些配置类,就不难根据实际需要写出自己的扩展版本。对于那些找不到AutoConfiguration配置类的,可结合框架的官方文档,使用@Configuration和@Bean注解自行进行配置。
http://emacoo.cn/blog/spring-boot-multi-db
【Spring】如何在单个Boot应用中配置多数据库?的更多相关文章
- tomcat中配置jndi数据库源
tomcat添加依赖 lib目录下添加依赖mysql-connector-java-8.0.16 配置数据源 介绍两种方法:tomcat中配置或web应用中配置 tomcat/conf/context ...
- Spring Cloud OAuth2.0 微服务中配置 Jwt Token 签名/验证
关于 Jwt Token 的签名与安全性前面已经做了几篇介绍,在 IdentityServer4 中定义了 Jwt Token 与 Reference Token 两种验证方式(https://www ...
- 如何在Django中配置MySQL数据库
直接上图 在项目中直接找到settings 文件 第一步 原始Django自带数据库 第二步将配置改成MySQL的数据 第三步 在__init__文件中告知Django使用MySQL数据 ...
- Druid中配置双数据库
配置如下 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://w ...
- 在python中配置MySQL数据库
MySQL数据库(1) 尽管用文件形式将数据保存到磁盘,已经是一种不错的方式.但是,人们还是发明了更具有格式化特点,并且写入和读取更快速便捷的东西——数据库(如果阅读港台的资料,它们称之为“资料库”) ...
- Django 中配置MySQL数据库
在Django的项目中会默认使用sqlite的数据库 配置MySQL需要在setting.py 里加入以下设置: 配置数据库 DATABASES = { 'default': { 'ENGINE': ...
- vs2013中配置SQLite数据库
转载:https://maplefan.com/index.php/2019/08/14/visual-studio-2013%e9%85%8d%e7%bd%aesqlite3%e7%9a%84%e6 ...
- webconfig中配置各种数据库的连接字符串(转)
一.在appSettings配置 <appSettings> <!--SQL Server--> <!--<add key="SQLString&qu ...
- webconfig中配置各种数据库的连接字符串
mysql连接串: <add name="ConnectionString" connectionString="Server=localhost;Database ...
随机推荐
- C语言文件函数
FILE *fp: 其中的FILE应该大写,它实际上是系统定义的一个结构,在stdio.h文件中.该结构中有文件名,文件状态,文件当前的读写信息等. fp是指向FILE结构的指针变量,通过fp可以找到 ...
- Python支持中文注释
三处设置,使Python的Eclipse开发环境(使用PyDev)支持中文 - (a)Eclipse的Window菜单Editors设置: Eclipse工具条 -> Window -> ...
- 【http】http/1.1 八种请求方式
OPTIONS 返回服务器针对特定资源所支持的HTTP请求方法.也可以利用向Web服务器发送'*'的请求来测试服务器的功能性. HEAD 向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回 ...
- ios应用启动后的自动版本检测方式
今天意外的发现了appstore居然还提供通过url获取json格式的客户端信息链接: http://itunes.apple.com/lookup?id=$id 通过此地址可以获取应用的icon.介 ...
- 自定义更新Hibernate Ehcache
最近在做一个项目中需要用缓存,项目持久层用的是Hibernate,然后就考虑用二级缓存来实现,但是后来项目扩展,由第三方修改数据这样缓存就会要等到失效后重新获取数据库的数据,本来这样是没问题的,可是领 ...
- matlab实现不动点迭代、牛顿法、割线法
不动点迭代 function xc = fpi( g, x0, tol ) x(1) = x0; i = 1; while 1 x(i + 1) = g(x(i)); if(abs(x(i+1) - ...
- Hadoop启动异常情况解决方案
1. 启动时报WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using b ...
- mysql中实现oracle中的rowid功能
mysql中没有函数实现,只能自己手动添加变量递增 := 就是赋值,只看红色字体就行 select @rownum:=@rownum+1,img.img_path,sku.sku_name from ...
- javacript中的mvc设计模式
以下内容为原创翻译,翻译不对的地方还请原谅,凑合着看吧. 原文网址是: 来源:http://www.alexatnet.com/articles/model-view-controller-mvc-j ...
- 3144:[HNOI2013]切糕 - BZOJ
题目描述 Description 经过千辛万苦小 A 得到了一块切糕,切糕的形状是长方体,小 A 打算拦腰将切糕切成两半分给小 B.出于美观考虑,小 A 希望切面能尽量光滑且和谐.于是她找到你,希望你 ...