複数のデータソースの一般的な使用シナリオ
- 複雑なビジネス (大量のデータ): ビジネスが複雑な場合は分割する必要があり、付随するデータベースも分割されるため、複数のデータベースが関係します。
- 読み取りと書き込みの分離: 静かなデータベース読み取りパフォーマンスの問題を解決するために (どちらも書き込みパフォーマンスよりも高いため、書き込みロックは読み取りブロックに影響し、読み取りパフォーマンスに影響します)
マルチデータソース構成の一般的な考え方
単一のデータ ソースの場合は getConnection で接続を取得するだけですが、
複数のデータ ソースを構成する場合は、接続を取得するときにどのデータベースの Connection を取得するかを判断する必要があります。
簡単な例
主に、複数のデータ ソース間で切り替えるロジックをデモンストレーションするために使用されます。
- まず依存関係 (通常の springboot、mybatis の依存関係) をインポートし、yml/properties を構成します。
spring:
datasource1:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/xxx_database1?serverTimezone=Asia/Shanghai
username: xxx
password: xxx
datasource2:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/xxx_database2?serverTimezone=Asia/Shanghai
username: xxx
password: xxx
次に、接続したデータベースのデータソースを Spring に登録します
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.datasource1")
public DataSource dataSource1(){
//底层会自动拿spring.datasource.datasource1的配置,然后创建一个DataSource
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.datasource2")
public DataSource dataSource2(){
return DruidDataSourceBuilder.create().build();
}
}
最後に、DynamicDataSource を作成します。DataSource の継承と
DataSource のオーバーライドには、多くのメソッドを書き直す必要があります。ここでは 1 つだけ示します。
@Component
@Primary //因为注册了很多DataSource,spring不知道要找哪个dataSource,所以用primary注解告诉服务器,主要进这个DataSource
public class DynamicDataSource implements DataSource {
@Resource
private DataSource dataSource1;
@Resource
private DataSource dataSource2;
@Override
public Connection getConnection() throws SQLException {
/*
这里写判断进入哪个数据库的逻辑,比如说dataSource1是写库,dataSource2是读库
可以在Controller里进行判断是读还是写,然后把他存到ThreadLocal里
然后在这里拿出ThreadLocal的值,做if else判断,从而拿到不同的数据库
*/
if(xxx){
return dataSource1.getConnection();
}else{
return dataSource2.getConnection();
}
}
}
これは、複数のデータ ソースを構成してデータベースに取り込むという一般的なアイデアですが、最終的な実装ではありません。
Spring は、さまざまなデータベースにアクセスするためのインターフェイスを構成します - AbstractRoutingDataSource()
このインターフェイスの機能は、どのデータベースにアクセスしたいかを伝えることであり、その後、直接アクセスするためにデータベース ソースから正しいデータベースを選択します。一般的なロジックは次のとおりです。実際、これは、私たちが作成したデモ ロジックに似ています
。
すべてのデータ ソースとデフォルトのデータ ソースが取得され、呼び出し時にデータ ソース識別子を指定すると、すべてのデータ ソースで必要なデータ ソースが検索され、getConnection が使用のために返されます。それを書き換えます
。
@Component
@Primary //将该bean设置为主要返回bean
public class DynamicDataSource extends AbstractRoutingDataSource {
public static ThreadLocal<String> name = new ThreadLocal<>();
@Resource
private DataSource dataSource1;
@Resource
private DataSource dataSource2;
/**
* 用于返回当前数据源标识
* @return {@link Object}
*/
@Override
protected Object determineCurrentLookupKey() {
return name.get();
}
/**
* 给
* targetDataSources 所有数据源
* defaultTargetDataSource 默认数据源
* 赋值
*/
@Override
public void afterPropertiesSet() {
//为targetDataSource附上所有数据源
Map<Object,Object> targetDataSources = new HashMap<>();
targetDataSources.put("main",dataSource1);
targetDataSources.put("plus",dataSource2);
super.setTargetDataSources(targetDataSources);
//为defaultDataSource附上默认数据源
super.setDefaultTargetDataSource(dataSource1);
super.afterPropertiesSet();
}
}
この時点で、DynamicDataSource の名前に値を直接割り当てて、データベースの切り替えを完了できます。
@GetMapping("test")
public void test(){
DynamicDataSource.name.set("main");
//数据库操作
}
AOPによる複数データソース切り替えの基本的な使い方です!