默认情况下,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
在我们日常产品发布的过程中,代码的版本控制可以使用git、svn工具实现。对于数据库每当发布时会出现手动执行sql脚本进行升级数据库,中间经常出现一些漏写、错写情况,对数据库的版本与代码的版本不匹配,导致上线后出现数据库不同步的问题。flyway就是对数据库版本进行控制的工具,可以对不同环境的sql进行迁移 *** 作。
flyway 的官网:https://flywaydb.org/
flyway会对每次执行过sql脚本保存到flyway_schema_history中,在数据库中将保存sql脚本的版本号和对sql生成checksum,当下次执行数据库迁移的时候就会按照版本号从低往高执行。如果以前的版本号脚本已经执行过就不会执行,如果以前版本的sql脚本已经被修改在执行的过程中则会报错。对flyway的详细描述与介绍可以查看flyway的官网。
配置好以上maven组件,在IDEA中就可以看到flyway的快捷插件了。
在插件中undo不能使用,undo为回滚 *** 作。回滚 *** 作只有使用商业版才能使用。
命令行执行
IDEA 工具执行(点击baseline、migrate)
使用migrate必须开头是V+版本号+“_ _“+描述.sql
如V1.0.3_20220618__increment.sql
对已经存在数据库schema结构的数据库的一种解决方案。实现在非空数据库新建metaData flyway_schema_history表,并把Migrations应用到该数据库;也可以在已有表格的数据库中添加metaData数据表。 注:对已有的数据结构的数据库来说,必须要进行baseline,才能进行migrate
清楚掉对应数据库Schema中所有的对象,包括表结构,视图,存储过程等,clean *** 作再dev和test阶段很好用,但是在生产环境务必禁用。
执行migrate会在指定文件夹下的sql按照版本号依次执行迁移 *** 作。也就是执行sql脚本,对已经执行过的sql脚本便不再执行。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)