Spring Bootデータソースのロードとそのマルチデータソースの簡単な実現について


ビジネスニーズ
  • は、すべてのマイクロサービスデータソースのグラフィカルメンテナンス機能
  • を提供する.
  • コード生成は、選択するデータソースに応じてテーブル等のソース情報
  • をロードすることができる.
  • データソース管理動的構成をサポートするには、
  • をリアルタイムで有効にします.
    付録効果図
    実現構想.
    本明細書では、単純なビジネスシーンと同様の方法を提供します.本番環境や複雑なビジネスシーンでは、ライブラリ分割テーブルのミドルウェア(mycaなど)やフレームワークsharding-sphere(使用中)などを使用してください.
  • Springのデフォルトのデータ・ソース・インジェクション・ポリシーを参照してください.次のコードのデフォルトのトランザクション・マネージャは、初期化時にデータ・ソースをロードして実装します.ここでは、動的データ・ソースのエントリ
  • です.
    //         
    ppublic class DataSourceTransactionManager extends AbstractPlatformTransactionManager
            implements ResourceTransactionManager, InitializingBean {
        
        //            
        public void setDataSource(@Nullable DataSource dataSource) {
            if (dataSource instanceof TransactionAwareDataSourceProxy) {
                this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource();
            }
            else {
                this.dataSource = dataSource;
            }
        }
    」
  • は、新しいDataSourceTransactionManagerを注入することによって実装され、複数のDataSourceを設定ことによって、マルチデータソース実装
  • を実現する.
  • Springがデフォルトで提供するルーティングデータソースフィールド
  • を参照
    public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {
        
        //              
        @Nullable
        private Map targetDataSources;
        //           
        @Nullable
        private Object defaultTargetDataSource;
        
        //        
        private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
        
        //           (             )
        @Nullable
        private Map resolvedDataSources;
    }

    手を出す
  • AbstractRoutingDataSourceを実装し、動的データソース実装を決定し、彼のルーティングキー検索方法を実装するだけでよい.

  • ここのルートキー対応は実はresolvedDataSources Mapのキーですよ
    @Slf4j
    public class DynamicDataSource extends AbstractRoutingDataSource {
    
        /**
         *     Key,         threadLocal    key   
         *
         * @return
         */
        @Override
        protected Object determineCurrentLookupKey() {
            return DynamicDataSourceContextHolder.getDataSourceType();
        }
    }
  • 私たちのダイナミックデータソース実装をSpringのトランザクションマネージャに注入し、データベースに行ってすべてのデータソース情報を検索し、具体的なデータソースを定義して私がここで使用しているHikariDataSourceを実装するなど
  • @Slf4j
    @Configuration
    @AllArgsConstructor
    public class DynamicDataSourceConfig implements TransactionManagementConfigurer {
        private final Map dataSourceMap = new HashMap<>(8);
        private final DataSourceProperties dataSourceProperties;
    
        @Bean("dynamicDataSource")
        public DynamicDataSource dataSource() {
            JdbcTemplate(dds).queryForList(DataSourceConstant.QUERY_DS_SQL);
            log.info("   ->         ");
            Optional.of(dbList).ifPresent(list -> list.forEach(db -> {
                log.info("   :{}", db.get(DataSourceConstant.DS_NAME));
                HikariDataSource ds = new HikariDataSource();
                dataSourceMap.put(db.get(DataSourceConstant.DS_ROUTE_KEY), ds);
            }));
            
            DynamicDataSource ds = new DynamicDataSource();
            ds.setTargetDataSources(dataSourceMap);
            return ds;
        }
    
        @Bean
        public PlatformTransactionManager txManager() {
            return new DataSourceTransactionManager(dataSource());
        }
    
        @Override
        public PlatformTransactionManager annotationDrivenTransactionManager() {
            return txManager();
        }
    
    }

    使用方法
    ユーザフロントで選択したデータソースkeyに従って、業務クラスでTTLに保存すればよく、自動的に選択に従ってデータソースをルーティングする
    DynamicDataSourceContextHolder.setDataSourceType(key)

    ここではもちろんAOPカスタム注釈などにより実現することも可能である.
    動的データ・ソースの動的構成方法
    上は実は私たちが望んでいる需要機能を完成しましたが、何か問題がありますか?私たちはデータソース管理面でデータソースを維持して、このdataSourceMapを動的に修正するのは実際には無効で、リアルタイムでリフレッシュすることはできません.
    AbstractRoutingDataSourceのロードmapデータソースのソースコードを見てみましょう.初期化時にafterPropertiesSetを呼び出して初期データソースmapを除去するだけです.
    では、現在のDynamicDataSourcebeanからafterPropertiesSetを手動で呼び出すだけでいいです.コード全体は次のとおりです.
    public class DynamicDataSourceConfig implements TransactionManagementConfigurer {
        private final Map dataSourceMap = new HashMap<>(8);
        private final DataSourceProperties dataSourceProperties;
        private final StringEncryptor stringEncryptor;
    
        @Bean("dynamicDataSource")
        public DynamicDataSource dataSource() {
            DynamicDataSource ds = new DynamicDataSource();
            HikariDataSource cads = new HikariDataSource();
            cads.setJdbcUrl(dataSourceProperties.getUrl());
            cads.setDriverClassName(dataSourceProperties.getDriverClassName());
            cads.setUsername(dataSourceProperties.getUsername());
            cads.setPassword(dataSourceProperties.getPassword());
            ds.setDefaultTargetDataSource(cads);
            dataSourceMap.put(0, cads);
            ds.setTargetDataSources(dataSourceMap);
            return ds;
        }
    
        /**
         *           ,       
         */
        @PostConstruct
        public void init() {
            DriverManagerDataSource dds = new DriverManagerDataSource();
            dds.setUrl(dataSourceProperties.getUrl());
            dds.setDriverClassName(dataSourceProperties.getDriverClassName());
            dds.setUsername(dataSourceProperties.getUsername());
            dds.setPassword(dataSourceProperties.getPassword());
    
            List> dbList = new JdbcTemplate(dds).queryForList(DataSourceConstant.QUERY_DS_SQL);
            log.info("   ->         ");
            Optional.of(dbList).ifPresent(list -> list.forEach(db -> {
                log.info("   :{}", db.get(DataSourceConstant.DS_NAME));
                HikariDataSource ds = new HikariDataSource();
                ds.setJdbcUrl(String.valueOf(db.get(DataSourceConstant.DS_JDBC_URL)));
                ds.setDriverClassName(Driver.class.getName());
                ds.setUsername((String) db.get(DataSourceConstant.DS_USER_NAME));
    
                String decPwd = stringEncryptor.decrypt((String) db.get(DataSourceConstant.DS_USER_PWD));
                ds.setPassword(decPwd);
                dataSourceMap.put(db.get(DataSourceConstant.DS_ROUTE_KEY), ds);
            }));
    
            log.info("   ->         ,   {}  ", dataSourceMap.size());
        }
    
        /**
         *          
         */
        public Boolean reload() {
            init();
            DynamicDataSource dataSource = dataSource();
            dataSource.setTargetDataSources(dataSourceMap);
            dataSource.afterPropertiesSet();
            return Boolean.FALSE;
        }
    
    
        @Bean
        public PlatformTransactionManager txManager() {
            return new DataSourceTransactionManager(dataSource());
        }
    
        @Override
        public PlatformTransactionManager annotationDrivenTransactionManager() {
            return txManager();
        }

    まとめ
  • 以上のソースコードリファレンス個人プロジェクトSpring Cloud、OAuth 2.0に基づいてVue前後分離に基づく開発プラットフォーム
  • を開発する.
  • QQ:2270033969 spring cloudの使い方について話しましょう.

  • もっと面白いJavaEEの実践に注目してください.