Ich schrieb ein Blog "Spring+MyBatis+MySQL, um ein verteiltes Datenbankzugriffs -Framework zu erstellen, bevor ich beschreibt, wie dynamische Datenquellen für Spring+MyBatis -Konfiguration auf mehrere Datenbanken zugreifen. Die vorherige Lösung hat jedoch einige Einschränkungen (auch im ursprünglichen Blog beschrieben): Sie gilt nur für Situationen, in denen die Anzahl der Datenbanken klein und behoben ist. Es gibt nichts über die Situation, in der die Datenbankdynamik zunimmt.
Das unten erwähnte Schema kann die dynamische Datenbankabnahme und -Löhe unterstützen, und die Nummer ist unbegrenzt.
Datenbankumgebungsvorbereitung
Hier ist MySQL als Beispiel: Erstellen Sie zuerst 3 Datenbanken vor Ort zum Testen. Es ist zu beachten, dass diese Lösung die Anzahl der Datenbanken nicht einschränkt und die Bereitstellung verschiedener Datenbanken auf verschiedenen Servern unterstützt. Wie in der Abbildung gezeigt, db_project_001, db_project_002, db_project_003.
Erstellen Sie ein Java Backend Microservice -Projekt
Erstellen Sie ein Spring Boot Maven -Projekt:
Konfiguration: Datenquellenkonfigurationsverwaltungsklasse.
DataSource: Die von selbst implementierte Datenquellenverwaltungslogik.
DBMGR: Verwaltet die Zuordnungsbeziehung zwischen Projektcodierung und Datenbank -IP und Name (dieser Teil der Daten im tatsächlichen Projekt wird im Redis -Cache gespeichert und kann dynamisch hinzugefügt und gelöscht werden).
Mapper: Datenbankzugriffsschnittstelle.
Modell: Mapping -Modell.
REST: Die erholsame Schnittstelle, die von Microservices nach außen veröffentlicht wurde und hier zum Testen verwendet wird.
application.yml: Konfigurieren Sie die JDBC -Parameter der Datenbank.
Detaillierte Code -Implementierung
1. Fügen Sie Datenquellenkonfiguration hinzu
Paket com.elon.dds.config; importieren javax.sql.datasource; import org.apache.ibatis.session.sqlSessionfactory; import org.mybatis.spring.SQLSessionFactoryBean; Importe org.mybatis.spring.Annotation.Mappercan; org.springframework.beans.factory.annotation.qualifier; import org.springframework.boot.autoconFigure.jdbc.datasourcebuilder; wichtig org.springframework.boot.context.properties.configurationProperties; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; Importieren Sie com.elon.dds.datasource.dynamicDataSource;/*** Datenquellenkonfigurationsmanagement. * * @Author Elon * @Version 26. Februar 2018 * / @configuration @mapperscan (Basepackages = "com.elon.dds.mapper", value = "SQLSessionFactory") öffentliche Klassen -DataSourceConfig { /** * Erstellen Sie Datenquellen basierend auf Konfigurationsparametern. Verwenden Sie abgeleitete Unterklassen. * * @Return Data Source */ @Bean (name = "dataSource") @ConfigurationProperties (Präfix = "Spring.DataSource") public DataSource getDataSource () {DataSourcebuilder builder = dataSourcebuilder.create (); Builder.Type (dynamicDataSource.class); return Builder.build (); } /*** Erstellen Sie eine Sitzungsfabrik. ** @param DataSource -Datenquelle* @return Session Factory*/ @bean (name = "sqlSessionFactory") public SQLSessionFactory GetQlSessionFactory (@Qualifier ("DataSource") DataSource -DataSource -DataSource) {sqleSessionFactoryBeanDean, = new SQLSessionFactoryBean (); Bean.setDataSource (DataSource); try {return bean.getObject (); } catch (Ausnahme e) {e.printstacktrace (); null zurückkehren; }}} 2. Definieren Sie dynamische Datenquellen
1) Fügen Sie zunächst eine Datenbankidentitätsklasse hinzu, um verschiedene Datenbankzugriffe zu unterscheiden.
Da wir separate Datenbanken für verschiedene Projekte erstellt haben, verwendeten wir die Projektcodierung als Index der Datenbank. Microservices unterstützen die Parallelität mit mehreren Threads und verwenden Threadvariablen.
Paket com.elon.dds.dataSource;/*** Datenbankidentitätsmanagementklasse. Wird verwendet, um verschiedene Datenbanken zu unterscheiden, die mit Datenquellen verbunden sind. * * @Author Elon * @Version 2018-02-25 */public class dBIdentifier {/** * Verwenden Sie verschiedene Projektcodierungen, um Datenbanken zu unterscheiden. public static String getProjectCode () {return projectCode.get (); } public static void setProjectCode (String -Code) {projectCode.set (Code); }}2) Eine DynamicDataSource erfolgt aus DataSource, wo dynamisches Umschalten von Datenbankverbindungen implementiert ist
importieren java.lang.reflect.field; import java.sql.connection; import java.sql.sqlexception; import org.apache.logging.log4j.logmanager; import org.apache.logging.log4j.logger; org.apache.tomcat.jdbc.pool.poolproperties; import com.elon.dds.dbmgr.projectdbmgr;/*** Definieren Sie die dynamischen Datenquellenableitungen Klassen. Abgeleitet von der grundlegenden Datenquelle, dynamisch von selbst implementiert. * * @Author Elon * @Version 2018-02-25 */public class dynamicDataSource erweitert DataSource {private static Logger log = logManager.getLogger (dynamicDataSource.class); /*** Diese Methode soll bei der Anforderung von Daten aus verschiedenen Projekten eine Verbindung zu verschiedenen Datenbanken herstellen. */ @Override public Connection getConnection () {String projectCode = dbIdentifier.getProjectCode (); // 1. Holen Sie sich die Datenquelle DataSource ddd = ddSolder.instance (). Getdds (projectCode); // 2. Create if (dds == null) {try {dataSource newdds = initdds (projectCode); DdSolder.instance (). Adddds (projectCode, newdds); } catch (illegalArgumentException | illegalAccessException e) {log.Error ("Init -Datenquelle fehlschlägt. ProjectCode:" + projectCode); null zurückkehren; }} dds = ddSolder.instance (). getdds (projectCode); try {return dds.getConnection (); } catch (sqlexception e) {e.printstacktrace (); null zurückkehren; }} /*** Kopieren Sie eine Kopie mit dem aktuellen Datenobjekt als Vorlage. * * @return dds * @throws illegalAccessException * @throws illegalArgumentException */ private dataSource initdds (String ProjectCode) löst IllegalArgumentException, illegalAccessException {dataSource dds = new DataSource () aus; // 2. kopieren Sie die Eigenschaften von PoolConfiguration PoolProperties Property = New PoolProperties (); Feld [] pfields = poolproperties.class.getDeclaredfields (); für (Feld f: pFields) {f.setAccessible (true); Object value = f.get (this.getPoolProperties ()); try {f.set (Eigenschaft, Wert); } catch (Ausnahme e) {log.info ("Wert fehlschlägen. Attrenname:" + f.getName ()); weitermachen; }} dds.setpoolProperties (Eigenschaft); // 3.. Setzen Sie den Datenbanknamen und die IP (im Allgemeinen werden Port, Benutzername und Kennwort einheitlich behoben) String urlformat = this.getUrl (); String url = string.format (urlFormat, projectDbmgr.instance (). Getdbip (projectCode), projectDBMgr.instance (). Getdbname (projectCode)); dds.seturl (URL); Rückgabe dds; }}3) Steuern Sie die Datenverbindungsfreigabe über DDStimer (Freigabe von nicht verwendeten Datenquellen, die die angegebene Zeit überschritten haben).
Paket com.elon.dds.datasource; import org.apache.tomcat.jdbc.pool.datasource;/*** Dynamic Data Source Timer Management. Die Datenbankverbindung, die lange Zeit keinen Zugriff hat, ist geschlossen. * * @Author Elon * @Version 25. Februar 2018 * /Public Class DdStimer { /** * Leerlaufzeitraum. Datenbankverbindungen, auf die nicht mehr als diese Zeit zugegriffen wurde, werden veröffentlicht. Die Standardeinstellung beträgt 10 Minuten. */ Private statische lange IdlePeriodenzeit = 10 * 60 * 1000; / *** Dynamische Datenquelle*/ private dataSource dds; / *** Letzte Zugriffszeit*/ privat lastusetime; public ddstimer (DataSource dds) {this.dds = dds; this.lastusetime = system.currentTimemillis (); } / *** Die neueste Zugriffszeit aktualisiert* / public void Refreshtime () {lastUsetime = System.currentTimemillis (); } /*** Erkennen Sie, ob die Datenverbindung aufgrund von Zeitüberschreitungen geschlossen ist. * * @return true - Timed Out; Falsch - nicht zeitlich ausgeführt*/ public boolean checkandClose () {if (System.currentTimemillis () - lastUsetime> IdlePeriodTime) {dds.close (); zurückkehren; } return false; } public DataSource getdds () {return dds; }}4) Fügen Sie DDScholder hinzu, um verschiedene Datenquellen zu verwalten und Datenquellenzusatz- und Abfragefunktionen bereitzustellen
Paket com.elon.dds.dataSource; import Java.util.hashMap; Import Java.util.iterator; import Java.util.map; import Java.util.map.Entry; * * @Author Elon * @Version 25. Februar 2018 * /öffentliche Klasse DDScholder { /** * Dynamische Datenquellenliste verwalten. <Projektcodierung, Datenquelle> */ private map <String, ddstimer> dddmap = new Hashmap <String, ddstimer> (); / *** Löschen Sie regelmäßig unbenutzte Datenquellen durch zeitgesteuerte Aufgaben*/ private statische Timer clearIdletask = new Timer (); static {clearIdletask.Schedule (neuer ClearIdLetImertask (), 5000, 60 * 1000); }; private ddSolder () {} /** Get Singleton -Objekt* / public static ddSolder Instance () {return ddSolderBuilder.instance; } /*** Dynamische Datenquelle hinzufügen. * * @param ProjectCode -Projektcodierung * @param dds dds */ public synchronisierte void adddds (String ProjectCode, DataSource DDS) {ddstimer ddst = new ddstimer (dds); ddsmap.put (projectCode, ddst); } / *** Dynamische Datenquelle abfragen** @param ProjectCode -Projektcodierung* @return dds* / public Synchronisierte DataSource getdds (String ProjectCode) {if (ddsmap.ContainsKey (projectCode)) {ddstimer ddst = ddsmap.get (projectCode); ddst.refreshtime (); return ddst.getDds (); } return null; } /*** Datenquellen löschen, die ohne jemanden zeitlich abgestimmt wurden. */ public synchronisierte void clearidddds () {iterator <Eintrag <String, ddstimer >> iter = ddsmap.EntrySet (). iterator (); für (; iter.hasnext ();) {Eintrag <String, ddstimer> Eintrag = iter.next (); if (Eintrag.getValue (). checkandClose ()) {iter.remove (); }}} / *** Singleton -Artefaktklasse* @Author Elon* @Version 26. Februar 2018* / private statische Klasse ddSolderbuilder {private statische DDSholder Instance = new ddSolder (); }}5) Timer Task ClearIdLetImertask wird verwendet, um die Leerlaufdatenquellen regelmäßig zu löschen
Paket com.elon.dds.dataSource; Import Java.util.TimerTask;/*** Aufgaben der Leerlaufverbindung. * * @Author Elon * @Version 26. Februar 2018 */public class clearIdletImertask erweitert Timertask {@Override public void run () {ddSolder.instance (). clearidddds (); }}3. Verwalten
Paket com.elon.dds.dbmgr; import java.util.hashMap; import Java.util.map;/*** Projektdatenbankverwaltung. Bietet eine Schnittstelle zum Abfragen von Datenbanknamen und IP basierend auf der Projektcodierung. * @Author Elon* @Version 25. Februar 2018* /Public Class ProjectDBMGR { /*** Speichern Sie die Zuordnungsbeziehung zwischen Projektcodierung und Datenname. Hier ist Hardcode. In der tatsächlichen Entwicklung können diese relationalen Daten im Redis -Cache gespeichert werden. * Hinzufügen eines neuen Projekts oder Löschen eines Projekts erfordert nur das Aktualisieren des Cache. Zu diesem Zeitpunkt muss die Schnittstelle dieser Klasse nur geändert werden, um Daten aus dem Cache abzurufen. */ private map <string, string> dbnamemap = new HashMap <String, String> (); /*** Speichern Sie die Zuordnungsbeziehung zwischen Projektcodierung und Datenbank -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 ProjectDBMgrin Instance () {return projectDBMgrBuilder.instance; } // In der tatsächlichen Entwicklung wird es geändert, um den öffentlichen String getdbName (String ProjectCode) {if (dbnamemap.containsKey (ProjectCode)) {return dbnamemap.get (projectCode); } zurückkehren ""; } // In der tatsächlichen Entwicklung ändern wir uns, um public String getDbip (String ProjectCode) {if (dbipmap.containsKey (projectCode)) {return dbipmap.get (projectCode); } zurückkehren ""; } private statische Klassenprojektdbmgrbuilder {private static projectDBMGRinstance = new ProjectDBMgr (); }} 4. Definieren Sie den Mapper für den Datenbankzugriff
Paket com.elon.dds.mapper; import java.util.list; import org.apache.ibatis.annotations.mapper; * MyBatis Mapping Interface Definition. * * @author elon * @version February 26, 2018*/@Mapperpublic interface UserMapper{ /** * Query all user data* @return User data list*/ @Results(value= { @Result(property="userId", column="id"), @Result(property="name", column="name"), @Result(property="age", column="age") }) @Select ("ID, Name, Alter aus TBL_USER") LIST <BENE> getUsers ();} 5. Definieren Sie das Query -Objektmodell
paket com.elon.dds.model; public class user {private int userId = -1; private String name = ""; privates int Alter = -1; @Override public String toString () {return "name:" + name + "| Alter:" + Alter; } public int getuSerId () {userID zurückgeben; } public void setUerId (int userId) {this.userId = userId; } public String getName () {return name; } public void setName (String -Name) {this.name = name; } public int getage () {return ay; } public void setage (int age) {this.age = älter; }} 6. Definieren Sie die erholsame Schnittstelle zum Abfragen von Benutzerdaten
Paket com.elon.dds.rest; import java.util.list; import org.springframework.bean.factory.Annotation.autowired; org. Schnittstelle. * * @Author Elon * @Version 26. Februar 2018 */ @rastController @RequestMapping (value = "/user") öffentliche Klasse WSUSER {@autowired private UsMapper UsMapper; /*** Abfragen Sie alle Benutzerinformationen im Projekt** @param ProjectCode Project Codierung* @return Benutzerliste*/@RequestMapping (value = "/v1/user", method = RequestMethod.get) publiclist <Benutzer> queryUser (@RequestParam (value = "projectCode", fordert = true projectCodode) {dBisitedPros.set- (projectCode ", fordert = true projectCode); return userMapper.getUsers (); }}Es ist erforderlich, dass der ProjectCode -Parameter in jeder Abfrage aufgenommen wird.
7. Schreiben Sie den Startcode für die Spring -Boot -App
Paket com.elon.dds; import org.springframework.boot.springapplication; import org.springframework.boot.autoconfigure.springbootApplication;/*** Hallo Welt! * */@SpringbootApplicationPublic Class App {public static void main (string [] args) {System.out.println ("Hallo Welt!"); SpringApplication.run (app.class, args); }} 8. Konfigurieren Sie die Datenquelle in application.yml
Der Datenbank -IP- und Datenbankname wird mit %s verwendet. Wechseln Sie dynamisch bei der Abfrage von Benutzerdaten.
Frühling: DataSource: URL: JDBC: MySQL: //%s: 3306/%s? UseUnicode = True & CharakterCoding = UTF-8 Benutzername: Root Kennwort: Treiberklassen-Name: com.mysql.jdbc.driverlogging: config: class: log4j2.xml.
Testplan
1. Fragen Sie die Daten von Project_001 ab und kehren Sie normal zurück
2. Fragen Sie die Daten von Project_002 ab und kehren Sie normal zurück
Zusammenfassen
Das obige ist der Implementierungscode für den Zugriff auf mehrere Datenbanken über die Dynamikdatenquellen für Spring -Startkonfiguration. Ich hoffe, es wird für alle hilfreich sein. Wenn Sie Fragen haben, hinterlassen Sie mir bitte eine Nachricht und der Editor wird allen rechtzeitig antworten. Vielen Dank für Ihre Unterstützung auf der Wulin.com -Website!