機能的要件は、会社が大規模な運用プラットフォームを構築する必要があることです。
1.オペレーションプラットフォームには独自のデータベースがあり、ユーザー、役割、メニュー、部品、許可などの基本的な機能を維持しています。
2。運用プラットフォームは、他の異なるサービス(サービスA、サービスB)のバックエンド操作も提供する必要があり、サービスAとサービスBのデータベースは独立しています。
したがって、操作プラットフォームは、オペレーションライブラリ、ライブラリ、およびBライブラリの3つのライブラリを接続する必要があります。各機能要求の対応するデータソースに自動的に切り替えることを望んでいます(私の最終実装は、サービスのメソッドレベルに切り替え、各DAO層のメソッドに切り替えることです。システムの機能は比較的独立しています)。
ステップ1:複数のデータソースを構成します
1。データソースを定義します。
私が使用するデータソースは、AlibabaのDruiddatasourceです(DBCPでは問題ありません、これは何でも)。構成は次のとおりです。
<! - op dataSource-> <bean id = "opdatasource" init-method = "init" destroy-method = "close"> <property name = "url" value = "$ {db.master.url}" /> <プロパティ名= "username" value = "$ {db.master.user}" value = "$ {db.master.password}" /> <property name = "driverclassname" value = "$ {db.master.driver}" /> <プロパティ名= "hiventsize" value = "5" /> <プロパティ名= "maxactive" value = "100" /> <property name = "" />> <" />> < <プロパティname = "validationQuery" value = "select 'x' '" /> <プロパティ名= "testonborrow" value = "false" /> <プロパティ名= "testonreturn" value = "false" /> <プロパティ名= "test whileidle" value = "true" /> <プロパティ名= "値= "300000" /> <プロパティ名= "removeabandoned" value = "true" /> <property name = "removeabandoneded timeout" value = "1800" /> <プロパティ名= "logabanded" value = "true" /> <! - 監視統計のためのフィルターの構成インターセプト - > <プロパティ= name = "connectionproperties" value = "config.decrypt = true" /> < /bean> <! - servera dataSource-> <bean id = "serveradatasource" init-method = "init-method =" close "> <property name =" url "value =" "$ {db.servera.master.url.urlama value = "$ {db.servera.master.user}" /> <property name = "password" value = "$ {db.servera.master.password}" /> <プロパティ名= "driverclassname" value = "$ {db.servera.master.driver}"値= "100" /> <プロパティ名= "minidle" value = "10" /> <プロパティ名= "maxwait" value = "60000" /> <プロパティ名= "validationquery" value = "select 'x' '" /> <プロパティ名= "testonborrow" value = "fals" /> <プロパティname = "fall" name = "testOnreturn" value = "false" /> <プロパティ名= "testhileidle" value = "true" /> <プロパティ名= "timeveevictionrunsmillis" value = "600000" /> <プロパティ名= "minevictableidletimemillis" value = "300000" />> <プロパティ= Value = "1800" /> <プロパティ名= "logabanded" value = "true" /> <! - 監視統計インターセプター用のフィルターの構成 - > <プロパティ名= "value =" config、mergestat、wall、log4j2 " /> <プロパティ名=" connectionproperties "value =" config.decryp = true " />> < /bean> < id = "serverbdatasource" init-method = "init" destroy-method = "close"> <property name = "url" value = "$ {db.serverb.master.url}" /> <プロパティ名= "username" value = "$ {db.serverb.master.user}" value = "$ {db.serverb.master.password}" /> <プロパティ名= "driverclassname" value = "$ {db.serverb.master.driver}" /> <プロパティ名= "hiantsize" value = "5" /> <プロパティname = "maxactive" 100 " /> <プロパティnam name = "maxwait" value = "60000" /> <プロパティname = "validationquery" value = "select 'x' '" /> <プロパティ名= "testonborrow" value "value" value " /> <property name =" testonreturn "" value = "false" /> <プロパティname = "testwhileidle" value = "" true " /> name = "minevictableidletimemillis" value = "300000" /> <プロパティ名= "removeabandoned" value = "true" /> <プロパティ名= "removeabandoned timeout" value = "1800" /> <プロパティ名= value = "config、mergestat、wall、log4j2" /> <プロパティ名= "connectionproperties" value = "config.decrypt = true" /> < /bean>OpdataSource(オペレーティングプラットフォーム自体のデータソース)、ServerDataSource、ServerBDataSourceの3つのデータソースを構成しました。
2。MultipLedataSourceを構成します
MultipledataSourceは、上記の3つのデータソースの1つのプロキシに相当します。 Spring/MyBatisと真に組み合わされている場合、多重延長と個別に構成されたDataSourceの使用は違いはありません。
<! - Spring Integration MyBatis:MultipLedataSourceを構成 - > <Bean Id = "SQLSessionFactory"> <Property Name = "DataSource" Ref = "MultipLedataSource" /> <! - 自動的にスキャンMapping.xmlファイル - > <プロパティname = <Mapperlocations "> <リスト> <リスト> <リスト> <value> classPath*:/sqlmapperxml/* value = "com.xxx.platform.model" /> <プロパティ名= "globalconfig" ref = "globalconfig" /> <プロパティ名= "プラグイン"> <配列> < value = "alidruid"/> </bean> </array> </property> </bean> <! - mybatis dynamic実装 - > <bean id = "mapperscannerconfigurer"> <! - daoインターフェイスの動的実装、インターフェイスがどこにあるかを知る必要があります - > <プロパティ " name = "sqlsessionfactorybeanname" value = "sqlsessionfactory"> </property> </bean> <! - mp global configuration-> <bean id = "globalconfig"> <property name = "idtype" value = "0"/> <プロパティ名= "dbcolumnunderline" <bean id = "transactionManager"> <プロパティ名= "dataSource" ref = "multipledatasource"> </property> </bean>
MultipledataSourceの場所を理解した後、MultipLedataSourceの実装方法に焦点を当てましょう。構成ファイルは次のとおりです。
<bean id = "multipledatasource"> <プロパティ名= "defaulttargetdatasource" ref = "opdatasource" /> <プロパティ名= "ターゲットダタソース"> <エントリkey = "opdatasource" opdatasource "opdatasource" key = "serverbdatasource" value-ref = "serverbdatasource"/> </map> </property> </bean>
実装されたJavaコードは次のとおりであり、あまり説明する必要はありません。
org.springframework.jdbc.datasource.lookup.abstractroutingdatasource;/** * * @classname:multipledatasource * @description:複数のデータソース<br> * @author:yuzhu.peng * @date:2018年1月12日、Mults25 pm/class abstractroutingDataSource {private static final threadlocal <string> dataSourcekey = new EnesteritableThreadLocal <String>(); public static void setDataSourcey(String DataSource){dataSourceKey.set(dataSource); } @Overrideプロテクションオブジェクトseciencurrentlookupkey(){return datasourcekey.get(); } public static void remodevedasourcekey(){dataSourceKey.remove(); }}SpringのAbstractroutingDataSourceから継承され、抽象的なメソッドsecurreantlookupkeyを実装します。このメソッドは、データベース接続が取得されるたびに、この接続のデータソースデータソースを決定します。スプリングコードが明確であることがわかります。
/*接続を取得*/ public Connection getConnection()squlecception {return sechineTargetDataSource()。getConnection(); }保護されたDataSource detienTargetDataSource(){assert.notnull(this.ResolvedDataSources、 "DataSource Router Not Initialized"); /*deciencurrentlookupkeyは、特定のデータソース名を取得する抽象インターフェイスです*/ object lookupkey = sechinecurrentlookupkey(); DataSource DataSource =(dataSource)this.ResolvedDataSources.get(lookupkey); if((datasource == null)&&(((this.lenientfallback)||(lookupkey == null))){dataSource = this.ResolvedDefaultDataSource; } if(dataSource == null){新しいIllegalStateExceptionをスロー( "LookupキーのターゲットDataSourceを決定できません[" + lookupkey + "]"); } dataSourceを返します。 } /*要約インターフェイス:つまり、MultipLedataSourceによって実装されたインターフェイス* /保護された抽象オブジェクトsecurrentlookupkey();ステップ2:すべてのリクエスト(サービスメソッドレベル)を動的に切り替える
実装のアイデアは、SpringのAOPアイデアを使用して各サービスメソッド呼び出しを傍受し、メソッドの全体的なパス名に従ってMultipLedataSourceのデータのキーを動的に切り替えることです。私たちのプロジェクトは、さまざまなサービスの運用、つまり異なるデータベースの操作であり、互いに独立しています。同じサービス方法で異なるデータソースを呼び出すことはお勧めしません。このようにして、スイッチングの頻度をDAOレベル、つまりSQLレベルに配置する必要があるかどうかを動的に判断する必要があります。さらに、トランザクション管理は便利ではありません。
動的スイッチングデータソースのAOP実装を見てみましょう。
java.lang.reft.proxy; import org.apache.commons.lang.classutils; import org.aspectj.lang.joinpoint; import org.aspectj.lang.annotation.aspect; import org.aspectj.lang.annotation.motion.before.before。 * * @author yuzhu.peng * @since 2018-01-15 * / @aspey @order(1)public class multipledatasourceInterceptor { /** *インターセプターは、すべてのビジネス実装クラスをリクエストする前に、データソースの切り替えに特別な注意を払っています。複数のデータソースが使用されるため、 *ServiceImplでのみMapperを呼び出すのが最善です。それ以外の場合、デフォルトのデータソースではないテーブルを呼び出す場合、テーブルに存在しない例外が報告されますJoinpoint.getTarget()。getClass();文字列className = clazz.getName(); if(classutils.isassignable(clazz、proxy.class)){classname = joinpoint.getSignature()。getDecLaringTypename(); } // serveraデータソースをクラス名で設定します。それ以外の場合は、デフォルトはバックグラウンドのデータソースですif(classname.contains( "。servera。")){multipledatasource.setdatasourcey(dbconstant.data_source_servera); } else if(classname.contains( "。serverb。")){multipledatasource.setDataSourcekey(dbconstant.data_source_serverb); } else {multipledatasource.setDataSourcekey(dbconstant.data_source_op); }} /***操作が完了すると、現在のデータソースがリリースされた場合、リリースされていない場合、頻繁にクリックするとデータソースの競合が発生します。これは別のデータソースの表ですが、別のデータソースに実行されます。レポートは存在しません** @param joinpoint* @throws throwable*/ @after( "execution(* com.xxxx.service ..*。* serviceimpl。*(..)")public void remodedatasoruce(joinpoint joinpoint)throws {multipledatasource.removedatasourcey(); }}すべてのServiceImplメソッドを傍受し、どのデータソース関数がメソッドの完全に適格な名前に属しているかを判断し、対応するデータソースを選択します。配布が完了したら、現在のデータソースを解放します。 Springの @Order、Annotationを使用したことに注意してください。次に、複数のAOPを定義するときに、注文が非常に便利であることに注意してください。
他の:
当初、プロジェクトはトランザクションを導入しなかったため、すべては問題ありませんでした。毎回正しいデータソースにアクセスできます。 Springのトランザクション管理に参加した後、データソースを動的に切り替えることはできません(トランザクションは効果的ではないようですが、2つは同時に有効ではありません)。その後、理由はAOPの実行順序であることがわかったので、上記の春の注文を使用しました。
順序が小さいほど、実行が最初になります。この時点で、データソースを動的に切り替えるだけでなく、(同じデータソースで)トランザクションを正常に使用することもできます。
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。