Spring+MyBatis構成のダイナミックデータソースを介して複数のデータベースにアクセスする方法を説明する前に、ブログ「Spring+MyBatis+MySQL」を作成しました。ただし、以前のソリューションにはいくつかの制限があります(元のブログでも説明されています)。データベースの数が小さく固定されている状況にのみ適用されます。データベースの動的が増加する状況については何もすることはありません。
以下に説明するスキームは、動的なデータベースの追加と削除をサポートでき、その数は無制限です。
データベース環境の準備
例としてMySQLがあります。最初にテスト用に3つのデータベースをローカルに構築します。このソリューションはデータベースの数を制限せず、異なるサーバー上の異なるデータベースの展開をサポートすることに注意する必要があります。図に示すように、db_project_001、db_project_002、db_project_003。
Javaバックエンドマイクロサービスプロジェクトを構築します
Spring Boot Mavenプロジェクトを作成します:
構成:データソース構成管理クラス。
DataSource:それ自体で実装されたデータソース管理ロジック。
DBMGR:プロジェクトエンコードとデータベースIPと名前の間のマッピング関係を管理します(実際のプロジェクトのデータのこの部分はRedisキャッシュに保存され、動的に追加および削除できます)。
マッパー:データベースアクセスインターフェイス。
モデル:マッピングモデル。
REST:Microservicesによって外側にリリースされたRESTFULインターフェイスは、ここでテストに使用されます。
Application.yml:データベースのJDBCパラメーターを構成します。
詳細なコード実装
1.データソースの構成を追加します
パッケージcom.elon.dds.config; Import javax.sql.datasource; Import org.apache.ibatis.session.squlsessionfactory; Import org.mybatis.spring.ssessionfactorybean; Import org.mybatis.spring.annotation.mapperscan; org.springframework.beans.factory.annotation.qualifier; Import org.springframework.boot.autoconfigure.jdbc.datasourcebuilder; import org.springframework.boot.context.properties.configurationproperties; org.springframework.context.annotation.beanをインポートします。 org.springframework.context.annotation.configurationをインポートします。 com.elon.dds.datasource.dynamicdatasource;/***データソース構成管理をインポートします。 * * @author elon * @version 2018年2月26日 * / @configuration @mapperscan(basepackages = "com.elon.dds.mapper"、value = "sqlsessionfactory")public class datasourceconfig { /** *構成パラメーターに基づいてデータソースを作成します。派生サブクラスを使用します。 * * @return data source */ @bean(name = "dataSource")@configurationProperties(prefix = "spring.datasource")public dataSource getDataSource(){dataSourceBuilder builder = dataSourceBuilder.create(); builder.type(dynamicdatasource.class); return builder.build(); } /***セッション工場を作成します。 ** @Param DataSource Data Source* @return Session Factory*/ @Bean(name = "sqlsessionFactory")public sqlsessionFactory getSqlSessionFactory( "dataSource")dataSource dataSource){sqlsessionfactorybean bean = new sqlsessionfactorybean(); Bean.SetDataSource(DataSource); try {return bean.getObject(); } catch(Exception e){e.printstacktrace(); nullを返します。 }}} 2。動的なデータソースを定義します
1)最初にデータベースIDクラスを追加して、さまざまなデータベースアクセスを区別します。
さまざまなプロジェクトに個別のデータベースを作成したため、データベースのインデックスとしてプロジェクトエンコードを使用しました。マイクロサービスは、マルチスレッドの並行性をサポートし、スレッド変数を使用します。
パッケージcom.elon.dds.datasource;/***データベースID管理クラス。データソースに接続されたさまざまなデータベースを区別するために使用されます。 * * @author elon * @version 2018-02-25 */public class dbidentifier {/** *さまざまなプロジェクトエンコーディングを使用してデータベースを区別します */private stathic threadlocal <string> projectcode = new threadlocal <string>(); public static string getProjectCode(){return ProjectCode.get(); } public static void setProjectCode(string code){projectCode.set(code); }}2)DynamicDataSourceは、データベース接続の動的スイッチングが実装されているDataSourceから派生しています
java.lang.Reflect.field; Import java.sql.Connection; Import Java.sql.sqlexception; Import org.apache.logging.log4j.logmanager; import org.apache.logging.log4j.logger; Import org.apache.tomcat.jdbc.pool.datas org.apache.tomcat.jdbc.pool.poolproperties; Import com.elon.elon.dds.dbmgr.projectdbmgr;/***ダイナミックデータソース派生クラスを定義します。基本的なDataSourceから導出され、それ自体で動的に実装されています。 * * @author elon * @version 2018-02-25 */public class dynamicdatasource拡張{private static logger log = logmanager.getlogger(dynamicdatasource.class); /***この方法は、さまざまなプロジェクトからデータを要求するときに、さまざまなデータベースに接続することです。 */ @Override public Connection getConnection(){String ProjectCode = dbidentifier.getProjectCode(); // 1。データソースDataSource dds = ddsholder.instance()。getDds(projectcode)を取得します。 // 2。 if(dds == null){try {dataSource newdds = initdds(projectcode); ddsholder.instance()。adddds(projectcode、newdds); } catch(IllegalargumentException | Illegalaccessexception e){log.Error( "initデータソースFail。projectCode:" + ProjectCode); nullを返します。 }} dds = ddsholder.instance()。getDds(projectcode); try {return dds.getConnection(); } catch(sqlexception e){e.printstacktrace(); nullを返します。 }} /***現在のデータオブジェクトをテンプレートとしてコピーします。 * * @return dds * @throws Illegalaccessexception * @throws Illegalargumentexception */ private dataSource initdds(String ProjectCode)IllegalArgumentException、Illegalaccessexception {dataSource dds = new DataSource(); //2。PoolConfigurationPoolPropertiesプロパティのプロパティをコピー= new PoolProperties(); field [] pfields = poolproperties.class.getDeclaredFields(); for(フィールドF:pfields){f.setAccessible(true);オブジェクト値= f.get(this.getPoolProperties()); try {f.set(property、value); } catch(Exception e){log.info( "set valuefail。thotlname:" + f.getname());続く; }} dds.setPoolProperties(Property); //3。データベース名とIP(通常、ポート、ユーザー名、パスワードが均一に固定されている)を設定しますstring urlformat = this.geturl(); string url = string.format(urlformat、projectdbmgr.instance()。getdbip(projectcode)、projectdbmgr.instance()。getdbname(projectcode)); dds.seturl(url); DDSを返します。 }}3)DDSTIMER(指定された時間を超えた未使用のデータソースのリリース)を介してデータ接続のリリースを制御する)
パッケージcom.elon.dds.datasource; Import org.apache.tomcat.jdbc.pool.datasource;/***ダイナミックデータソースタイマー管理。長い間アクセスできないデータベース接続は閉じられています。 * * @author elon * @version 2018年2月25日 * /public class ddstimer { /** *アイドル期間。この時間以上アクセスされていないデータベース接続がリリースされます。デフォルトは10分です。 */ private static long idleperiodtime = 10 * 60 * 1000; / ***動的データソース*/プライベートデータソースDDS; / ***最後のアクセス時間*/プライベート長lastUSETIME; public ddstimer(datasource dds){this.dds = dds; this.lastusetime = system.currenttimemillis(); } / ***最新のアクセス時間を更新* / public void refreshtime(){lastuseTime = system.currenttimemillis(); } /***タイムアウトのためにデータ接続が閉じられているかどうかを検出します。 * * @return true-タイムアウト; false-タイミングではありません*/ public boolean checkandclose(){if(system.currenttimemillis() - lastusetime> idleperiodtime){dds.close(); trueを返します。 } falseを返します。 } public dataSource getDds(){return dds; }}4)DDSholderを追加してさまざまなデータソースを管理し、データソースの追加およびクエリ機能を提供します
パッケージcom.elon.dds.datasource; Import java.util.hashmap; Import java.util.iterator; Import java.util.map; Import java.util.map.entry; Import java.util.timer; Import org.apache.tomcat.jdbc.poo.pool.pool.datasource。 * * @author elon * @version 2018年2月25日 * /public class ddsholder { /** *動的データソースリストを管理します。 <プロジェクトエンコード、データソース> */プライベートマップ<文字列、ddstimer> ddsmap = new Hashmap <String、ddstimer>(); / ***タイムされたタスクを介して未使用のデータソースを定期的にクリア*/プライベート静的タイマーClearIdletask = new Timer(); static {clearIdletask.schedule(new clearIdletimertask()、5000、60 * 1000); }; private ddsholder(){} /** singleton object* / public static ddsholder instance(){return ddsholderbuilder.instance; } /***動的データソースを追加します。 * * @Param ProjectCode Project Encoding * @Param DDS DDS */ public Synchronized void addDDS(String ProjectCode、DataSource DDS){ddstimer ddst = new ddstimer(dds); ddsmap.put(projectcode、ddst); } / *** query dynamic data source** @param projectcodeプロジェクトエンコード* @return dds* / public synchronized datasource getDds(String ProjectCode){if(ddsmap.containskey(projectcode)){ddstimer ddst = ddsmap.get(projectcode); ddst.refreshtime(); ddst.getdds()を返します。 } nullを返します。 } /***誰なしでタイムアウトされた明確なデータソース。 */ public Synchronized void clearidledds(){iterator <entry <string、ddstimer >> iter = ddsmap.entryset()。iterator(); for(; iter.hasnext();){entry <string、ddstimer> entry = iter.next(); if(entry.getValue()。checkandclose()){iter.remove(); }}} / *** singleton artifact class* @author elon* @version 2018年2月26日* / private static class ddsholderbuilder {private static ddsholder instance = new ddsholder(); }}5)タイマータスクClearIdleTimertaskは、定期的にアイドルデータソースをクリアするために使用されます
パッケージcom.elon.dds.datasource; Import java.util.timertask;/***クリアアイドル接続タスク。 * * @author elon * @version 2018年2月26日 */public class clearidletimertask extends timertask {@override public void run(){ddsholder.instance()。cleariddds(); }}3.データベースIPおよび名前とのマッピング関係をエンコードするプロジェクトを管理する
パッケージcom.elon.dds.dbmgr; Import java.util.hashmap; Import java.util.map;/***プロジェクトデータベース管理。プロジェクトエンコーディングに基づいて、データベース名とIPをクエリするインターフェイスを提供します。 * @author elon* @version 2018年2月25日* /パブリッククラスprojectdbmgr { /***プロジェクトエンコードとデータ名の間のマッピング関係を保存します。これがハードコードです。実際の開発では、このリレーショナルデータはRedisキャッシュに保存できます。 *新しいプロジェクトを追加するか、プロジェクトを削除するには、キャッシュのみを更新する必要があります。当時、このクラスのインターフェイスは、キャッシュからデータを取得するために変更する必要があります。 */ private Map <string、string> dbnamemap = new hashmap <string、string>(); /***プロジェクトエンコードとデータベースIPの間のマッピング関係を保存します。 */ private Map <string、string> dbipmap = new hashmap <string、string>(); private projectdbmgr(){dbnamemap.put( "project_001"、 "db_project_001"); dbnamemap.put( "project_002"、 "db_project_002"); dbnamemap.put( "project_003"、 "db_project_003"); dbipmap.put( "project_001"、 "127.0.0.1"); dbipmap.put( "project_002"、 "127.0.0.1"); dbipmap.put( "project_003"、 "127.0.0.1"); } public static projectdbmgr instance(){return projectdbmgrbuilder.instance; } //実際の開発では、パブリック文字列getDbname(String ProjectCode)を取得するために変更されます。if(dbnamemap.containskey(projectcode)){return dbnamemap.get(projectcode); } 戻る ""; } //実際の開発では、パブリック文字列getDBIP(String ProjectCode)を取得するために変更されます{dbipmap.containskey(projectcode)){return dbipmap.get(projectcode); } 戻る ""; } private static class projectdbmgrbuilder {private static projectdbmgr instance = new ProjectDbmgr(); }} 4.データベースアクセス用のマッパーを定義します
パッケージcom.elon.dds.mapper; Import java.util.list; import org.apache.ibatis.annotations.mapper; Import org.apache.ibatis.annotations.Result; Import org.apache.ibatis.annotations.ansults; import org.apache.ibatis.annotations.nelect.me.el.medd. MyBatisマッピングインターフェイス定義。 ** @author elon* @version 2018年2月26日*/ @mapperpublicインターフェイスusermapper {/*** queryすべてのユーザーデータ* @returnユーザーデータリスト*/@results( @result( @resid "、column =" id ")、@result(=" column = "column =" ")、columm @Select( "id、name、age from tbl_user"を選択)<user> getusers();} 5。クエリオブジェクトモデルを定義します
パッケージcom.elon.dds.model; public class user {private int userid = -1;プライベート文字列name = ""; Private int age = -1; @Override public String toString(){return "name:" + name + "| age:" + age; } public int getUserid(){return userid; } public void setuserid(int userid){this.userid = userid; } public string getname(){return name; } public void setName(string name){this.name = name; } public int getage(){return age; } public void Setage(int age){this.age = age; }} 6.ユーザーデータを照会するためのRESTFULインターフェイスを定義します
パッケージcom.elon.dds.rest; import java.util.list; import org.springframework.beans.factory.annotation.autowired; import org.springframework.web.bind.annotation.requestmapping; import org.springframework.web.bind.annotation.annotation.requestmeth; org.springframework.web.bind.annotation.RequestParam; Import org.springframework.web.bind.annotation.restController; Import com.elon.dds.datasource.dbidentifier; Import com.elon.dds.mapper.usermapr.ddss.mapper;インターフェイス。 * * @author elon * @version 2018年2月26日 */ @restcontroller @requestmapping(value = "/user")public class wsuser {@autowired private usermapper usermapper; /***プロジェクトのすべてのユーザー情報** @Param ProjectCodeプロジェクトエンコード* @returnユーザーリスト*/@RequestMapping(value = "/v1/users"、method = requestmethod.get)public list <user> queryuser(@requestparam(value = "projectode"、rebure = ruece)string projectode) return usermapper.getusers(); }}各クエリにProjectCodeパラメーターを含める必要があります。
7.Spring Bootアプリのスタートアップコードを書きます
パッケージcom.elon.dds; Import org.springframework.boot.springApplication; Import org.springframework.boot.autoconfigure.springbootapplication;/*** Hello World! * */@SpringBootApplicationPublic Class App {public static void main(string [] args){system.out.println( "hello world!"); SpringApplication.run(app.class、args); }} 8。application.ymlでデータソースを構成します
データベースIPおよびデータベース名は%sで使用されます。ユーザーデータのクエリを動的に切り替えます。
スプリング:DataSource:URL:JDBC:mysql://%s:3306/%s?useunicode = true&Charaterencoding = utf-8ユーザー名:ルートパスワード:ドライバークラス名:com.mysql.jdbc.driverlogging:config:classpath:log4j2.xml
テスト計画
1. project_001のデータをクエリし、正常に返します
2。project_002のデータをクエリし、正常に返します
要約します
上記は、Spring Boot Configurationの動的データソースを介して複数のデータベースにアクセスするための実装コードです。私はそれが誰にでも役立つことを願っています。ご質問がある場合は、メッセージを残してください。編集者は、すべての人に時間内に返信します。 wulin.comのウェブサイトへのご支援ありがとうございます!