同じプロジェクトには、複数のデータベース、つまり複数のデータソースが含まれる場合があります。複数のデータソースを2つの状況に分けることができます。
1)2つ以上のデータベースには相関関係がなく、互いに独立しています。実際、これは2つのプロジェクトとして開発できます。たとえば、ゲーム開発では、1つのデータベースはプラットフォームデータベースであり、プラットフォームの下のゲームに対応するもう1つのデータベースも利用できます。
2)2つ以上のデータベースは、MySQLがマスターマスターを構築するなど、マスタースレーブ関係です。その後、複数の奴隷が続きます。またはMHAで構築されたマスタースレーブコピー。
現在、春のマルチデータソースを構築する方法は約2つの方法があり、マルチデータソースの状況に応じて選択できます。
1.スプリング構成ファイルを使用して、複数のデータソースを直接構成する
たとえば、2つのデータベース間に相関がない場合、Spring構成ファイルで複数のデータソースを直接構成し、以下に示すようにトランザクション構成を実行できます。
<コンテキスト:Component-Scanベースパッケージ= "net.aazj.service、net.aazj.aop" /> <コンテキスト:component-scanベースパッケージ= "net.aazj.aop" /> <! - プロパティファイルの紹介 - > <コンテキスト:プロパティプレイスホルダー場所= "classpath:config /db.porperties" />> <! init-method = "init" destroy-method = "close"> <プロパティ名= "url" value = "$ {jdbc_url}" /> <プロパティ名= "username" value = "$ {jdbc_username}" />> <プロパティ名= "パスワード" value = "$ {jdbc_password} value = "0" /> <! - 接続プールで使用される接続の最大数 - > <プロパティ名= "Maxactive"値= "20" /> <! - 利用可能な接続の最大数 - > <プロパティ名= "maxidle"値= "20" /> <! value = "60000"/> </bean> <bean id = "sqlsessionfactory"> <プロパティ名= "datasource" ref = "dataSource"/> <プロパティ名= "configlocation" value = "classpath:config/mybatis-config.xml"/> <プロパティ名= "config/mappers//" /> < /bean> <! - 単一のjdbc dataSourceのトランザクションマネージャー - > <bean id = "transactionmanager"> <property name = "dataSource" ref = "dataSource" /> < /bean> <! - 注釈を使用したトランザクションを否定する - > <tx:<tx:nuntation driven transaction-manager = <<bean value = "net.aazj.mapper"/> <プロパティ名= "sqlsessionfactorybeanname" value = "sqlsessionfactory"/> </bean> <! - spring aopの@aspectjスタイルの使用を有効にします - > <aop:aspectj-autoproxy/>>2番目のデータソースの構成
<bean name = "datasource_2" init-method = "init" destroy-method = "close"> <プロパティ名= "url" value = "$ {jdbc_url_2}" /> <プロパティ名= "username" value = "$ {jdbc_username_2}" /> <時間 - > <プロパティ名= "maxwait" value = "60000" /> < /bean> <bean id = "sqlsessionfactory_slave"> <Property name = "datasource" ref = "datasource_2" /> <プロパティ名= "configlocation" value = "classpath:configis-config-2.xml" /> < value = "classpath*:config/mappers2/**/*。xml"/> </bean> <! - 単一のJDBC DataSourceのトランザクションマネージャー - > <bean id = "transactionmanager_2"> <プロパティ名= "dataSource" ref = "datasource_2"/> </bean> < Transaction-Manager = "TransactionManager_2" /> <bean> <プロパティ名= "basepackage" value = "net.aazj.mapper2" /> <プロパティ名= "sqlsessionfactorybeanname" value = "sqlsessionfactory_2" /> < /bean> < /bean>上記のように、2つのDataSources、2つのSQLSessionFactory、2つのTransactionManagers、およびMapperScanCannOconFigurerの構成にキーを構成します。このようにして、異なるデータベースに対応するマッパーインターフェイスに対応するSQLSessionFactoryを注入します。
複数のデータベースのこの構成は、分散トランザクションをサポートしていないことに注意してください。つまり、同じトランザクションで複数のデータベースを操作できないことに注意してください。この構成の利点は、非常に簡単であることですが、柔軟ではありません。マスタースレーブタイプのマルチデータソースの構成にはあまり適していません。マスタースレーブタイプのマルチデータソースの構成は、特に柔軟である必要があり、ビジネスの種類に応じて詳細な構成が必要です。たとえば、いくつかの時間のかかる選択ステートメントの場合、それらをスレーブに載せたいと考えています。更新、削除、その他の操作のために、マスターでのみ実行できます。さらに、リアルタイムの要件が高いいくつかの選択されたステートメントの場合、マスターにそれらを置く必要がある場合があります。たとえば、シナリオでは、武器を購入するためにモールに行きます。購入操作は間違いなくマスターです。購入が完了した後、私が所有する武器と金貨を再クエリットする必要があります。また、このクエリは、マスターでそれらが実行されないようにする必要がある場合があり、奴隷に遅延がある可能性があるため、奴隷で実行することはできません。購入が成功した後、バックパックに武器を見つけることができないことをプレイヤーに見つけてほしくありません。
したがって、マスタースレーブタイプのマルチデータソースの構成のために、奴隷に選択でき、選択を奴隷に配置することはできないビジネスに応じて柔軟な構成が必要です。したがって、データソースの上記の構成はあまり適していません。
2。AbstractroutingDataSourceとAOPに基づくマルチデータソースの構成
基本原則は、DataSourceクラスのスレッドロカルロングダタソースを定義して、AbstractroutingDataSourceを継承し、マスターとスレーブのデータソースを構成ファイルのThreadLoctlountingDataSourceに挿入し、AOPを介して柔軟に構成し、マスターデータソースを選択する場所を選択する場所を柔軟に構成することです。以下のコードの実装を見てみましょう。
1)最初に異なるデータソースを表す列挙を定義します。
パッケージnet.aazj.enums; /** *データのカテゴリソース:Master/Slave */public Enum DataSources {Master、Slave} 2)ヘッドローカルを使用して、各スレッドに選択するデータソースのキーを保存します。
パッケージnet.aazj.util; net.aazj.enums.datasourcesをインポートします。パブリッククラスDataSourCeTypeManager {private static final threadlocal <dataSources> dataSourceTypes = new ThreadLocal <DataSources>(){@Override Protected DataSources initialValue(){return dataSources.master; }}; public static dataSources get(){return dataSourcetypes.get(); } public static void set(dataSources dataSourcetype){dataSourcetypes.set(dataSourcetype); } public static void reset(){dataSourcetypes.set(dataSources.master0); }} 3)ThreadLocalRountingDataSourceを定義し、AbstractroutingDataSourceを継承します。
パッケージnet.aazj.util; Import org.springframework.jdbc.datasource.lookup.abstractroutingdatasource; public class threadlocalrountingdatasource extends abstractroutingdatasource {@overrideプロテクションオブジェクトdecurrentlookupkey(){return datasourcetypemanager.get(); }}4)構成ファイルにマスターとスレーブのデータソースをthreadLocalRountingDataSourceに注入します。
<コンテキスト:Component-Scanベースパッケージ= "net.aazj.service、net.aazj.aop" /> <コンテキスト:component-scanベースパッケージ= "net.aazj.aop" /> <! - プロパティファイルの紹介 - > <コンテキスト:プロパティプレイスホルダー場所= "classpath:config /db.porperties" />>>>> < init-method = "init" destroy-method = "close"> <プロパティ名= "url" value = "$ {jdbc_url}" /> <プロパティ名= "username" value = "$ {jdbc_username}" />> <プロパティ名= "パスワード" value = "$ {jdbc_password} value = "0" /> <! - 接続プールで使用される接続の最大数 - > <プロパティ名= "Maxactive"値= "20" /> <! - 利用可能な接続の最大数 - > <プロパティ名= "maxidle"値= "20" /> <!値= "60000" /> < /bean> <! - データソーススレーブの構成 - > <bean name = "datasourceslave" init-method = "init" destroy-method = "close"> <property name = "url" value = "$ {jdbc_url_slave}" /> <プロパティ= "$" " <プロパティname = "password" value = "$ {jdbc_password_slave}" /> <! - 初期化接続サイズ - > <プロパティname = "hirtingize" value = "0" /> <! - 接続プールで使用される接続の最大数 - > <プロパティ名= <プロパティname = "maxactive" value = "20" /> <アイドル接続プール - > <プロパティ名= "minidle" value = "0" /> <! - 最大接続待機時間を取得 - > <プロパティ名= "maxwait" value = "60000" /> < /bean> <bean id = "dataSource"> <プロパティ名= " key-type = "net.aazj.enums.datasources"> <entry key = "master" value-ref = "datasourcemaster"/> <entry key = "slave" value-ref = "datasourceslave"/> <! - 複数のデータソースをここに追加できます - > </財産> </bean name = "dataSource" ref = "dataSource"/> <プロパティ名= "configlocation" value = "classpath:config/mybatis-config.xml"/> <プロパティ名= "mapperlocations" value = "classpath*:config/mappers/**/*。xml"/> </bean> <! id = "transactionManager"> <プロパティ名= "dataSource" ref = "dataSource" /> < /bean> <! - アノテーションを使用したトランザクションの定義 - > <tx:notation-driven transaction-manager = "transactionmanager" /> <bean> <propertial name = "basepackage" name = "sqlsessionfactorybeanname" value = "sqlsessionfactory"/> - > </bean>上記のSpring構成ファイルでは、マスターデータベースとスレーブデータベースのDataSourCemasterとDataSourcesLaveをそれぞれ定義し、<Bean ID = "DataSource">に挿入して、DataSourceが異なるキーに従ってDataSourCemasterとDataSourcesLaveを選択できるようにします。
5)Spring AOPを使用してDataSourceのキーを指定するため、DataSourceはキーに従ってDataSourCemasterとDataSourcesLaveを選択します。
パッケージnet.aazj.aop; net.aazj.enums.datasources; Import net.aazj.util.datasourcetypemanager; org.aspectj.lang.joinpoint; Import org.aspectj.lang.annotation.aspect; import org.aspectj.lang.annotation.before; import org.aspectj.lang.annotation.pointcut; import org.springframework.stereotycome.component; @aspect // for aop @component // for auto scanpublic class datasourceinterceptor {@pointcut( "execution(public * net.aazj.service .. *。getuser(..))")public void dataSourceslave(){}; @before( "dataSourcesLave()")public void before(joinpoint jp){datasourcetypemanager.set(dataSources.slave); } // ...}ここでは、アスペクトクラスを定義します。 @beforeを使用して@pointcut( "execution(public * net.aazj.service .. *。getUser(..))に準拠してメソッドの前にdatasourcetypemanager.set(dataSources.slave)を呼び出します。したがって、このメソッドのSQLステートメントは、スレーブデータベースで実行されます。
DataSourceInterceptorの側面を継続的に拡張し、その中にさまざまな定義を作成して、特定のサービスメソッドの適切なデータソースに対応するDataSourceを指定できます。
このようにして、Spring AOPの強力な機能を使用して、非常に柔軟に構成できます。
6)AbstractroutingDataSourceの原理の分析
ThreadLocalRountingDataSourceは、AbstractroutingDataSourceを継承し、その抽象メソッドを実装しました。したがって、さまざまなデータソースにルーティング関数を実装します。ソースコードから始めて、原則を分析しましょう。
パブリックアブストラクトクラスAbstractroutingDataSourceは、AbstractDataSourceを拡張します。次に、スプリングがBeanを初期化すると、InitializingBean void afterpropertiesset()のスロー例のインターフェイスを呼び出します。 AbstractroutingDataSourceがこのインターフェイスをどのように実装するかを見てみましょう:@Override public void abutPropertiesset(){if(this.targetdatasources == null){throw new Illegalargumentexception( "Property 'TargetDataSources'が必要です"); } this.ResolvedDataSources = new Hashmap <Object、dataSource>(this.targetdatasources.size()); for(map.entry <object、object> entry:this.targetdatasources.entryset()){object lookupkey = resolvespecified lookupkey(entry.getKey()); DataSource DataSource = ResolvesPecifiedDataSource(entry.getValue()); this.ResolvedDataSources.put(lookupkey、dataSource); } if(this.defaultTargetDataSource!= null){this.ResolvedDefaultDataSource = ResolvesPecifiedDataSource(this.DefaultTargetDataSource); }} TargetDataSourcesは、XML構成ファイルに注入するDataSourCemasterとDataSourcesLaveです。 AfterPropertiessetメソッドが注入されます。
DataSourCemasterとDataSourcesLave HashMap -ResolvedDataSourcesを構築します。キーに応じて、マップから対応するデータソースを後で取得するのが便利です。
接続getConnection()がどのようにsqlexceptionをスローするかを見てみましょう。 AbstractDataSourceインターフェイスが実装されています。
@Override public connection getConnection()throws sqlexception {return sechineTargetDataSource()。getConnection(); }重要なのは、メソッド名に基づいて見ることができるDetineTargetDataSource()を決定することです。ここで使用するDataSourceを決定する必要があります。
保護されたDataSource sechIneTargetDataSource(){assert.notnull(this.ResolvedDataSources、 "DataSource Router Not Initialized"); object lookupkey = sechinecurrentlookupkey(); DataSource DataSource = this.ResolvedDataSources.get(lookupkey); if(dataSource == null &&(this.lenientfallback || lookupkey == null)){dataSource = this.ResolvedDefaultDataSource; } if(dataSource == null){新しいIllegalStateExceptionをスロー( "LookupキーのターゲットDataSourceを決定できません[" + lookupkey + "]"); } dataSourceを返します;} object lookupkey = sechinecurrentlookupkey();この方法は当社によって実装されており、そこではキー値をthreadlocalで保存します。キーを取得した後、MAPのキーに対応するデータソースを取得します。 Threadlocalで保存されたキー値は、AOPを介してサービスに関連するメソッドを呼び出す前に設定されます。わかりました、ここで完了です!
3。概要
この記事から、AOPのパワーと柔軟性を体験できます。
上記は、MyBatis Multi-DATAソース処理の情報並べ替えです。困っている友達を助けることができることを願っています