最近、私はマージンバランスクエリの最適化を行っています。プロジェクトが開始されると、すべてのライダーのマージンバランスを完全に照会する必要があるため、バランスをローカルキャッシュに完全にロードする必要があります。メインデータベースのパフォーマンスに影響を与えないために、クエリを離れることを検討してください。そのため、プロジェクトで複数のデータソースを構成し、動的に切り替える必要があります。いくつかの調査の後、動的スイッチングが完全に実現され、参照用に構成方法が記録されます。
全体的なデザインのアイデア
Spring-Boot+AOPメソッドマルチデータソースの切り替えを実現し、AbstractroutingDataSourceを継承して動的なデータソースの取得を実現し、サービスレイヤーでの注釈を使用してデータソースを指定します。
ステップ
1。マルチデータソース構成
Application.Propertiesでは、構成はこのようなものです
#マスターデータソースdruid.master.url = jdbc:mysql:// url/masterdb?useunicode = true&charatereCoding = utf8&zerodateTimeBehior = converttonulldruid.master.username = xxxdruid.master.password = 123dru id.master.driver-class-name = com.mysql.jdbc.driverdruid.master.max-wait = 5000druid.master.max-active = 100druid.master.test-on-borrow = truedruid.master.validation-query = selectデータソースからdruid.slave.url = jdbc:mysql:// url/slavedb?useunicode = true&charatereCoding = utf8&zerodatetimebehavior = converttonulldruid.slave.username = xxxdruid.slave.password = 123dru id.slave.driver-class-name = com.mysql.jdbc.driverdruid.slave.max-wait = 5000druid.slave.max-active = 100druid.slave.test-on-borrow = truedruid.slave.validation-query = select 1
構成を読み取ります
<! - マスターデータソース - > <beanプライマリ= "true" id = "masterdb" init-method = "init" destroy-method = "close"> <! - 基本プロパティURL、ユーザー、パスワード - > <プロパティ名= "driverclassName" value = " name = "username" value = "$ {druid.master.username}"/> <property name = "password" value = "$ {druid.master.password}"/> <! - 最大初期化を構成 - > <プロパティname = "maxactive" value = "$ {druid.mastive.max-active | < name = "maxwait" value = "$ {druid.master.max-wait}"/> <property name = "validationquery" value = "$ {druid.master.validation-query}"/> <プロパティ= "testonborrow" value = "$ {druid.master.test-on-borrow}プライマリ= "true" id = "slavedb" init-method = "init" destroy-method = "close"> <! - 基本プロパティURL、ユーザー、パスワード - > <プロパティ名= "driverclassName" value = "com.mysql.jdbc.driver"/> <プロパティ名= "url" value = " value = "$ {druid.slave.username}"/> <property name = "password" value = "$ {druid.slave.password}"/> <! - 設定初期化サイズ、最小、> <プロパティname = "maxactive" value = "$ {druid.sluid.slave.max-active time < name = "maxwait" value = "$ {druid.slave.max-wait}"/> <プロパティ名= "validationquery" value = "$ {druid.slave.validation-query}"/> <プロパティname = "testonborrow" value = "$ {druid.slave.test on-borrow}サービスインターフェイスの注釈に基づいて取得 - > <bean id = "dataSource"> <プロパティ名= "ターゲットダタソース"> <マップキータイプ= " name = "DefaultTargetDataSource" ref = "masterdb"/> </bean> <! - spring jdbctemplate-> <bean id = "jdbctemplate"> <プロパティname = "datasource" ref = "datasource"/> </bean> <! - スプリングトランザクションマネージャーref = "dataSource"/> </bean> <bean id = "transactionTemplate"> <プロパティ名= "transactionManager" ref = "transactionManager"/> </bean> <tx:annotation-driven-manager = "transactionmanager" proxy-target-class = "true"/< id = "sqlsessionfactory"> <プロパティ名= "dataSource" ref = "dataSource"/> <プロパティ名= "mapperlocations" value = "classpath*:mapper-xxdb/*mapper*.xml"/> </bean> <bean> <財産名= "basepackage" value = "xxdb.mapper"/> name = "sqlsessionfactorybeanname" value = "sqlsessionfactory"/> </bean>2。動的なデータソース
Springは、ルーティングのあるデータソースであるAbstractroutingDataSourceを提供します。継承した後、実際のデータソース名のルーティング方法をカスタマイズするために使用されるsecienCurrentlookupkey()を実装する必要があります。情報をThreadlocalに保存するため、それを取り出す必要があります。
パブリッククラスのdynamicdatasourceは、abstractroutingdatasourceを拡張します{private logger logger = loggerfactory.getLogger(this.getClass()); @Overrideプロテクションオブジェクトseciencurrentlookupkey(){string dataSource = jdbccontextholder.getDataSource(); logger.info( "データソースは{}"、dataSource); DataSourceを返します。 }}3。データソースの動的スイッチングクラス
動的なデータソースの切り替えはAOPに基づいているため、AOPセクションを宣言し、セクションの前でデータソースの切り替えを行う必要があります。セクションが完了すると、データソース名が削除されます。
@aspeed @order(1)// AOP実行注文を設定します(トランザクションの前に必要です。そうしないと、トランザクションはデフォルトのライブラリでのみ発生します)@componentPublicクラスDataSourceaspect {private logger logger = loggerFactory.getLogger(this.getClass()); // cut point @pointcut( "execution(*com.xxx.service。*。*(..)")public void aspeats(){} @before( "aspeed()")private void before(joinpoint point){object target = point.getTarget(); string method = point.getSignature()。getName(); Class <? try {method m = classz.getMethod(method、parametertypes); if(m!= null && m.isannotationpresent(mydatasource.class)){mydatasource data = m.getannotation(mydatasource.class); logger.info( "method:{}、dataSource:{}"、m.getname()、data.value()。getname()); jdbccontextholder.putdatasource(data.value()。getname()); //データソースを現在のスレッドに置きます}} catch(exception e){logger.error( "get datasource error"、e); // Master jdbccontextholder.putdatasource(datasourcetype.master.getName()); //データソースを現在のスレッドに置きます}} @afterturning( "aspeet()")public void after(joinpoint point){jdbccontextholder.cleardatasouse(); }}4。データソース管理カテゴリ
パブリッククラスjdbccontextholder {private final static threadlocal <string> local = new threadlocal <>(); public static void putdatasource(string name){local.set(name); } public static string getDataSource(){return local.get(); } public static void clearDataSource(){local.remove(); }}5。データソースの注釈と列挙
データソースを切り替えると、通常、特定のインターフェイスのメソッドを呼び出す前に実装するため、メソッドアノテーションを定義します。 AOPがメソッドに注釈が存在することを検出すると、注釈の値に対応する名前に応じて切り替えます。
@retention(RetentionPolicy.Runtime)@Target(elementType.Method)public @interface mydatasource {dataSourceType value();} public enum dataSourcetype {// master( "master")、// slave( "slave");プライベート文字列名; private dataSourceType(string name){this.name = name; } public string getname(){return name; } public void setName(string name){this.name = name; }}6。カットポイントアノテーション
動的なデータソースにはデフォルトのライブラリがあるため、メソッドがデフォルトライブラリを操作する場合、注釈は必要ありません。非デフォルトデータソースを操作する場合は、@MyDataSource( "DataSource名")注釈をメソッドに追加して、AOPを使用して動的スイッチングを実現できるようにする必要があります。
@componentpublic class xxxserviceimpl {@resource private xxxmapperext xxxmapperext; @mydatasource(value = datasourcetype.slave)public list <object> getall(){return xxxmapperext.getall(); }}上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。