【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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM