ホームページ  >  記事  >  Java  >  Springboot で複数のデータソースを構成する方法

Springboot で複数のデータソースを構成する方法

无忌哥哥
无忌哥哥オリジナル
2018-07-20 11:22:282270ブラウズ

要約: プロジェクトで使用されている現在の永続化フレームワークは mybatis です。分析の結果、マルチデータ ソース構成では 2 つの問題を解決する必要があることがわかります。1 つは、元の Spring のクラシック メソッドから Springboot メソッドに切り替える方法です。複数のデータソースを設定するには?大きな変化はありましたか?もう 1 つは、複数のデータ ソースを mybatis の構成に関連付ける方法です。

まえがき

最近、プロジェクトのニーズにより、著者は Springboot マルチデータ ソース構成の旅に着手しました。著者は以前に Spring の動的なマルチデータ ソースの切り替えを構成したことがありますが、そのときは JDBC テンプレートを使用しました。

プロジェクトで使用されている現在の永続化フレームワークは mybatis です。分析の結果、マルチデータ ソース構成では 2 つの問題を解決する必要があることがわかります。1 つは、元の Spring のクラシック メソッドから Springboot メソッドに切り替えることです。複数のデータソースを設定しますか?大きな変化はありましたか?もう 1 つは、複数のデータ ソースを mybatis の構成に関連付ける方法です。

まず、単一のデータ ソースで mybatis を構成する方法を見てみましょう。

単一のデータ ソースの例

まず最初に、プロジェクトが単一のデータ ソースのみに依存している場合、Springboot が代わりに処理を行っても構わない場合は、おめでとうございます。トラブルを避けることができます。プロジェクトのプロパティ ファイルにデータ ソースの関連プロパティ構成を追加するだけで、springboot によってデータ ソースが「無料」で提供されます。デフォルトは tomcat jdbc 接続プールです。

もちろん、Springboot の親切を拒否することもできます。サードパーティの接続プール テクノロジに依存する場合は、独自のデータ ソースを構成できます。その場合、Springboot は、DataSource が自分で定義されたことを検出した後、データ ソースを自動的に構成しません。

作者は springboot の好意を断ることができないので、プロジェクトの application.properties に次のプロパティのみを追加しました:

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.max-idle=10
spring.datasource.max-wait=10000
spring.datasource.min-idle=5
spring.datasource.initial-size=5
spring.datasource.validation-query=SELECT 1
spring.datasource.test-on-borrow=false
spring.datasource.test-while-idle=true
spring.datasource.time-between-eviction-runs-millis=18800
然后笔者创建了一个专门用于配置mybatis的类,如下:
@Configuration
public class MybatisSpringConfig {
@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setTypeAliasesPackage("demo.model");
return factoryBean.getObject();
}
[[[@Bean](http://my.oschina.net/bean)](http://my.oschina.net/bean)](http://my.oschina.net/bean)
public MapperScannerConfigurer mapperScannerConfigurer() {
    MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
    mapperScannerConfigurer.setBasePackage("demo.repository");
    return mapperScannerConfigurer;
}
}

はい、mybatis はこのような簡単な構成で春には正常に動作します。 mybatis の設定ファイルを意図的に作成したり、マッパー インターフェイスを登録したり、対応する XML ファイルの場所を指定したりする必要はありません。これは完全に mybatis-spring によるもので、Mybatis と spring を簡単に実行できる「接着剤」のようなものです。一緒に「接着」されています。

MyBatis-Spring の設定手順

まず、mybatis-spring 設定の一般的な手順について説明します。

  1. データ ソース DataSource の Bean を設定します。

  2. DataSource を使用してトランザクション マネージャーを構成します。

  3. DataSourceを使用してSqlSessionFactoryのBeanを設定します。

  4. MapperScannerConfigurer Bean を構成します。

構成されたトランザクション マネージャーと SqlSessionFactory のデータ ソースが同じである必要があります。同じでない場合、トランザクション管理は機能しません。 MapperScannerConfigurer を構成する目的は、マッパー インターフェイスが配置されているパッケージを自動的にスキャンし、マッパー インターフェイスを Bean (エージェント生成インターフェイスの実装クラス) として登録して、依存関係に直接使用できるようにすることです。マッパー インターフェイスとそれに対応する XML ファイルを同じパッケージに配置することをお勧めします。そのため、SqlSessionFactory で XML ファイルの場所を指定する必要はありません。

OK、上で投稿した設定内容と比較すると、いくつかの手順を見逃した理由がわかるかもしれません? springboot のおかげで、DataSource が自動的に構成されるため、トランザクション マネージャーも自動的に構成されます。したがって、作成者は SqlSessionFactory と MapperScannerConfigurer のみを構成しました。

もちろん、これを見た後でも独自のデータ ソースを構成したい場合は、以下のマルチ データ ソース構成手順を参照して、複数のデータ ソースの 1 つを抽出して、カスタムの単一データ ソース構成を実現してください。

複数のデータソースの例

上記の単一のデータソースの例の後、コードを書くために springboot に切り替えると、springboot は非常に便利であり、カスタマイズに影響を与えないと言えます。そのため、著者は使用する前に次のように考えています。 springboot を使用すると、どのような構成で spring を使用しても、springboot を使用した後は障害がなくなり、以前よりも高速になります。

複数のデータ ソースを必要とするシナリオについて簡単に説明します。著者は他の記事を参照し、そのニーズのほとんどがデータベースのマスター/スレーブ方式または読み取り/書き込み分離から来ていることを発見しました。次に、マスターとスレーブの 2 つのデータ ソースに応じて、データ ソースの構成クラスを直接ポストします。

  • application.properties

datasource.master.url=jdbc:mysql://localhost:3306/master
datasource.master.username=root
datasource.master.password=root
datasource.master.driver-class-name=com.mysql.jdbc.Driver
datasource.master.max-idle=10
datasource.master.max-wait=10000
datasource.master.min-idle=5
datasource.master.initial-size=5
datasource.master.validation-query=SELECT 1
datasource.master.test-on-borrow=false
datasource.master.test-while-idle=true
datasource.master.time-between-eviction-runs-millis=18800
datasource.slave.url=jdbc:mysql://localhost:3306/slave
datasource.slave.username=root
datasource.slave.password=root
datasource.slave.driver-class-name=com.mysql.jdbc.Driver
datasource.slave.max-idle=10
datasource.slave.max-wait=10000
datasource.slave.min-idle=5
datasource.slave.initial-size=5
datasource.slave.validation-query=SELECT 1
datasource.slave.test-on-borrow=false
datasource.slave.test-while-idle=true
datasource.slave.time-between-eviction-runs-millis=18800
  • マスターデータソース

@Configuration
public class MasterConfig {
[[[@Primary](http://my.oschina.net/primary)](http://my.oschina.net/primary)](http://my.oschina.net/primary)
@Bean(name = "masterDataSource")
@ConfigurationProperties(prefix = "datasource.master")
public DataSource dataSource() {
    return DataSourceBuilder.create().build();
}

@Primary
@Bean(name = "masterTransactionManager")
public DataSourceTransactionManager transactionManager(@Qualifier("masterDataSource") DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
    }
}

  • スレーブ データ ソース

@Configuration
public class SlaveConfig {
    @Bean(name = "slaveDataSource")
    @ConfigurationProperties(prefix = "datasource.slave")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build(){
    }
    @Bean(name = "slaveTransactionManager")
    public DataSourceTransactionManager transactionManager(@Qualifier("slaveDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

2 つのデータ ソースの構成手順を確認するのは難しくありません。

  1. プロパティ ファイルで 2 つのデータ ソースに必要な属性値を構成し、プレフィックス名に注意してください。

  2. 2 つのデータ ソースの構成クラスを構築する もちろん、これらを 1 つの構成クラスにスタックすることは悪い考えではありません。

  3. 設定クラスで、DataSource の Bean を設定します。識別できる名前を付けることを忘れないでください。

  4. 2 つのデータ ソースに対応するトランザクション マネージャーを構成します。面倒なことはしないでください。そうしないと、識別できる名前を付けることになります。

配置DataSource时,利用@ConfigurationProperties(prefix = "xxx.xxx")可以依靠指定的前缀,在诸多的属性值中“挑选”出数据源依赖的属性,进而完成数据源的构建。

当自己定义了DataSource后,springboot就会取消自动配置的动作了。为了各司其职,为每个数据源配置各自的事务管理器,springboot自然也会取消自动配置事务管理器的动作。由于是多个数据源和多个事务管理器,都是一个类型的,你要是不起个区别的名字,任谁都分辨不出来吧?

@Primary 有什么作用呢?简单地说,当有两个同一类型的Bean,依赖注入时你没有指定name,正常情况下会报错,有两个你要的Bean,识别不了。但是 @Primary 相当于指定这个Bean为默认的,如果你没有指定name,就采用 @Primary 标识的Bean。

OK,两个数据源的配置配好了,还需要配置各自的Mybatis来进行持久化的操作。

MyBatis-Spring相关配置

  • mybatis for master

@Configuration
@MapperScan(basePackages = {"demo.repository.master"}, sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterConfig {
    @Primary
    @Bean(name = "masterDataSource")
    @ConfigurationProperties(prefix = "datasource.master")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }
@Primary
@Bean(name = "masterTransactionManager")
public DataSourceTransactionManager transactionManager(@Qualifier("masterDataSource") DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}
@Primary
@Bean(name = "masterSqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("masterDataSource") DataSource dataSource) throws Exception {
    SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
    factoryBean.setDataSource(dataSource);
    factoryBean.setTypeAliasesPackage("demo.model");
    return factoryBean.getObject();
}
}

  • mybatis for slave

@Configuration
@MapperScan(basePackages = {"demo.repository.slave"}, sqlSessionFactoryRef = "slaveSqlSessionFactory")
public class SlaveConfig {
@Bean(name = "slaveDataSource")
@ConfigurationProperties(prefix = "datasource.slave")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "slaveTransactionManager")
public DataSourceTransactionManager transactionManager(@Qualifier("slaveDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "slaveSqlSessionFactory")
public SqlSessionFactory basicSqlSessionFactory(@Qualifier("slaveDataSource") DataSource basicDataSource) throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(basicDataSource);
factoryBean.setTypeAliasesPackage("demo.model");
return factoryBean.getObject();
}
}

这里需要强调几个地方:

  1. 细心人会发现上面的配置类中,少了MapperScannerConfigurer的Bean配置,改用了@MapperScan注解。其实两者的作用是一样的,但是@MapperScan比较新,稍后会做解释为什么它比较新。

  2. 由于两个数据源的原因,引出了两套SqlSessionFactory的配置,所以@MapperScan中需要指明依赖的是哪个SqlSessionFactory,“sqlSessionFactoryRef”对应就是SqlSessionFactory的name属性。

  3. @MapperScan会将扫描的mapper接口代理生成实现类,并自动注册为Bean。由于两个数据源的配置类中都有@MapperScan注解,为了避免造成冲突和排错时的困扰,猛烈提醒,两个数据源的配置,mybatis对应的mapper接口及对应xml文件也构建两套,最好接口名上也做些区分。model类使用同一套倒是没什么影响。所以你会看到上面的配置中,@MapperScan中basePackages指向的是两个包路径。

好了,来解释下@MapperScan为何比较新,并且笔者推荐使用@MapperScan。

首先@MapperScan要求的mybatis-spring版本比较新,说明它是新推出的特性。

其次@MapperScan要比配置MapperScannerConfigurer的Bean要简练的多,代码量上就看得出来。

最后,@MapperScan中的basePackageClasses属性是MapperScannerConfigurer所没有的。并且笔者用到了这个basePackageClasses属性,所以这里强力推荐使用@MapperScan注解。

多聊一些,描述下笔者为何会用到@MapperScan中的basePackageClasses属性吧,况且与上述示例中的basePackages有何区别呢?

上面提到了多数据源的一般场景,笔者的不同。笔者的项目中划分了n个子模块,每个子模块有各自的数据库,现在需要每个子模块共享一个公共信息的数据库。

从代码上来说,由于各个子模块依赖的公共信息数据库-数据源、mapper接口和xml映射文件是相同的,笔者希望将这些类和文件抽离到maven的一个公共module(最后会打包为一个jar文件)中,供其他n个子模块依赖使用,这样可以避免重复代码嘛。

笔者这么做之后,发现配置MapperScannerConfigurer的basePackages找不到mapper接口所在的包路径,因为笔者是在子模块中配置的MapperScannerConfigurer,它自然会在子模块的结构中去寻找指定的包路径,是mapper接口被笔者放到了公共的module中,所以是找不到的!

不过还好在@MapperScan中发现了basePackageClasses属性,它会“接受”你指定的mapper接口的全名。再次提醒,记得把xml映射文件和mapper接口放在一起,mybatis-spring会帮你做关联。

以上がSpringboot で複数のデータソースを構成する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。