SpringBoot構成読み書き分離


前言
このケースは、MySQLマスターの構成に基づいて行われます.
1.まずアプリケーション.propertiesで2つのデータソースを構成
SpringBootで自動的に構成されたdataSorceを使用する必要はなく、名前に注意してください.
spring.master.username=root
spring.master.password=admin
spring.master.url=jdbc:mysql:///MS
spring.master.driver-class-name=com.mysql.jdbc.Driver


spring.slave1.username=root
spring.slave1.password=
spring.slave1.url=jdbc:mysql://localhost:3307/MS
spring.slave1.driver-class-name=com.mysql.jdbc.Driver

2.DataSourceの構成クラスの作成@ConfigurationPropertiesラベルを使用して構成情報を読み取り、接続プールオブジェクトを作成します.
@Bean
@ConfigurationProperties(prefix = "spring.master")
public DataSource masterds(){
    return new DruidDataSource();
}

@Bean
@ConfigurationProperties(prefix = "spring.slave1")
public DataSource slaveds(){
    return new DruidDataSource();
}

ここで、new DruidDataSource()ではなく、DataSourceBuilder.create().build()でdataSourceオブジェクトを作成してもよい.この場合、urlをjdbc-urlに構成し、dataSourceのtypeを構成する必要があることに注意する.
3.クラス実装AbstractRoutingDataSourcelクラスをカスタマイズし、書き換え方法
public class MSRoutingDataSource extends AbstractRoutingDataSource {
    /*
    *     key   ,  DataSource       DataSource   ,            ,              DataSource
    * */
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContext.getDataSource();
    }
}

この方法では、DataSourceContextは、現在のスレッドにバインドされたデータソース名をカプセル化したクラスであり、データソースの設定とデータソースの取得は、このスレッドで異なる時点で動作するため、ThreadLocalを使用して動作する
@Component
public class DataSourceContext {


    // ThreadLocal      ,                 
    private static ThreadLocal<String> dataSourcePool = new ThreadLocal<>();

    public static String getDataSource() {
        return dataSourcePool.get();
    }

    public static void setDataSource() {
        dataSourcePool.set("slaveds");
    }

}

4.このルーティングを設定するdataSource
@Bean
public MSRoutingDataSource dataSource(@Qualifier("masterds") DataSource masterds,
                                        @Qualifier("slaveds") DataSource slaveds){
    MSRoutingDataSource routingDataSource =  new MSRoutingDataSource();
    Map<Object,Object> targetDataSources = new HashMap<>();
    targetDataSources.put("masterds",masterds);
    targetDataSources.put("slaveds",slaveds);
    routingDataSource.setDefaultTargetDataSource(masterds);
    routingDataSource.setTargetDataSources(targetDataSources);
    return routingDataSource;
}

プロジェクトを開始すると、エラーが表示され、プロジェクトの開始にループが発生したと言います.
***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:

   basicInfoController (field private cn.kiring.ms.base.service.IUserInfoService cn.kiring.ms.base.controller.BasicInfoController.userInfoService)
      ↓
   userInfoServiceImpl (field private cn.kiring.ms.base.mapper.UserInfoMapper cn.kiring.ms.base.service.impl.UserInfoServiceImpl.userInfoMapper)
      ↓
   userInfoMapper defined in file [F:\JavaAc\Idea\ms\ms-parent\ms-core\target\classes\cn\kiring\ms\base\mapper\UserInfoMapper.class]
      ↓
   sqlSessionFactory defined in class path resource [org/mybatis/spring/boot/autoconfigure/MybatisAutoConfiguration.class]
┌─────┐
|  dataSource defined in class path resource [cn/kiring/ms/ApplicationCoreConfig.class]
↑     ↓
|  masterds defined in class path resource [cn/kiring/ms/ApplicationCoreConfig.class]
↑     ↓
|  org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker

これはコンフィギュレーションクラスが独自のdataSourceを自動的に使用するコンフィギュレーションです.この場合、この自動コンフィギュレーションクラスの使用を手動でキャンセルする必要があります.
5.関連するすべてのSpringApplication構成クラスでdataSourceの自動構成を解除する
// SpringBootApplication     exclude
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})

この時プロジェクトを起動して、またエラーが発生して、報告したのは
***************************
APPLICATION FAILED TO START
***************************

Description:

A component required a bean of type 'org.springframework.transaction.PlatformTransactionManager' that could not be found.
	- Bean method 'transactionManager' not loaded because @ConditionalOnSingleCandidate (types: javax.sql.DataSource; SearchStrategy: all) did not find a primary bean from beans 'slaveds', 'masterds', 'dataSource'


Action:

Consider revisiting the entries above or defining a bean of type 'org.springframework.transaction.PlatformTransactionManager' in your configuration.

このプロジェクトはトランザクションを使用しているため、プライマリdatasourceが何であるかは指定されていません(datasource自動構成がキャンセルされているため)、トランザクションを設定する必要があります.
6.SpringBootマルチデータソースの場合、トランザクションの構成
  • 方式一:メインbean
  • を設定する
    // MSRoutingDataSourced bean   @Primary  
    @Bean
    @Primary
    public MSRoutingDataSource dataSource(@Qualifier("masterds") DataSource masterds,
                                            @Qualifier("slaveds") DataSource slaveds){
        MSRoutingDataSource routingDataSource =  new MSRoutingDataSource();
        Map<Object,Object> targetDataSources = new HashMap<>();
        targetDataSources.put("masterds",masterds);
        targetDataSources.put("slaveds",slaveds);
        routingDataSource.setDefaultTargetDataSource(masterds);
        routingDataSource.setTargetDataSources(targetDataSources);
        return routingDataSource;
    }
    
  • 方式2:PlatformTransactionManagerのbeanを独自に構成し、dataSource
  • をインポート
     @Bean
    public PlatformTransactionManager platformTransactionManager(MSRoutingDataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);//     
    }
    

    このときConfigur起動クラスの構成コードを貼り付ける
    @SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
    @EnableTransactionManagement
    
    @MapperScan(basePackages = "cn.kiring.ms.*.mapper")
    public class ApplicationCoreConfig {
    
        @Bean
        @ConfigurationProperties(prefix = "spring.master")
        public DataSource masterds(){
            return new DruidDataSource();
        }
    
        @Bean
        @ConfigurationProperties(prefix = "spring.slave1")
        public DataSource slaveds(){
            return new DruidDataSource();
        }
    
        @Bean
        public MSRoutingDataSource dataSource(@Qualifier("masterds") DataSource masterds,
                                               @Qualifier("slaveds") DataSource slaveds){
            MSRoutingDataSource routingDataSource =  new MSRoutingDataSource();
            Map<Object,Object> targetDataSources = new HashMap<>();
            targetDataSources.put("masterds",masterds);
            targetDataSources.put("slaveds",slaveds);
            routingDataSource.setDefaultTargetDataSource(masterds);
            routingDataSource.setTargetDataSources(targetDataSources);
            return routingDataSource;
        }
    
        @Bean
        public PlatformTransactionManager platformTransactionManager(MSRoutingDataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);//     
        }
    
    }
    

    これによりSpringBootのマスタースレーブの構成が整うようになり、このときリクエストごとにスレーブデータベースが使用されているわけではなく、DataSourceContext.setはサービスに設定されており、トランザクションを使用する場合、setの前にデータソースの名前をgetしますが、この場合名前は空です( , @Transaction , determineCurrentLookupKey )ので、プライマリ(デフォルト)データベースアクセスがメイン(デフォルト)です.
    7.AoPを使用してdatasourceを制御する
    サービスでdatasourceを設定すると、使用するdatasourceがデフォルトであり、自分が使用したいデータソースではないため、aopプリエンハンスメントを使用して操作し、DataContextを変更する
    public class DataSourceContext {
        @Pointcut("execution(* cn.kiring.ms.base.service.impl.IpLogServiceImpl.query(..))")
        public void routingPoint(){}
    
    
        private static ThreadLocal<String> dataSourcePool = new ThreadLocal<>();
    
        public static String getDataSource() {
            return dataSourcePool.get();
        }
    
        @Before("routingPoint()")
        public static void setDataSource() {
            dataSourcePool.set("slaveds");
        }
    }