Funktionelle Anforderungen sind, dass das Unternehmen eine große Betriebsplattform erstellen muss:
1. Die Operationsplattform verfügt über eine eigene Datenbank, in der grundlegende Funktionen wie Benutzer, Rollen, Menüs, Teile und Berechtigungen beibehalten werden.
2. Die Betriebsplattform muss auch Back-End-Vorgänge anderer verschiedener Dienste (Service A, Service B) und die Datenbanken von Service A und Service B unabhängig bereitstellen.
Daher muss die Operationsplattform mindestens drei Bibliotheken verbinden: Betriebsbibliothek, eine Bibliothek und B -Bibliothek, und hoffen, für jede Funktionsanforderung automatisch zur entsprechenden Datenquelle zu wechseln (meine endgültige Implementierung besteht darin, auf die Methodenebene des Dienstes zu wechseln und auf die Methode jeder DAO -Ebene zu wechseln. Die Funktionen unseres Systems sind relativ unabhängig voneinander).
Schritt 1: Konfigurieren Sie mehrere Datenquellen
1. Definieren Sie die Datenquelle:
Die Datenquelle, die ich verwende, ist Alibabas DruiddataSource (es ist in Ordnung mit DBCP, das ist was auch immer). Die Konfiguration ist wie folgt:
<!-op dataSource-> <bean id = "opdataSource" init-method = "init" destroy-method = "close"> <Eigenschaft name = "url" value = "$ {db.master.url}" /> <Eigenschaft name = "username" value = "$ {DB.Master.usser}" /> < value = "$ {db.master.Password}" /> <Eigenschaft name = "triverClassName" value = "$ {db.master.driver}" /> <Eigenschaft name = "initialSize" value = "5" /> <Property name = "maxactive" value = "100" /> <Eigenschaft ". name = "validationQuery" value = "select 'x'" /> <Eigenschaft name = "testonborrow" value = "false" /> <Eigenschaft name = "testonReturn" value = "false" /> <Eigenschaft name = "test während value="300000" /> <property name="removeAbandoned" value="true" /> <property name="removeAbandonedTimeout" value="1800" /> <property name="logAbandoned" value="true" /> <!-- Configure filters for monitoring statistics intercept --> <property name="filters" value="config,mergeStat,wall,log4j2" /> <property name = "ConnectionProperties" value = "config.decrypt = true" /> < /bean> <!-servera dataSource-> <bean id = "serveradataSource" init-method = "init" init "-Method =" close "> <Property name =" url "value =" $ {{DB.SERVERA.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER.MASTER}} " /> <{{uservera". value = "$ {db.servera.master.user}" /> <Eigenschaft name = "Passwort" value = "$ {db.servera.master.Password}" /> <Eigenschaft name = "driverClassName" value = "$ {db.servera.master.driver}" /> <Mandstellsname "=" mach = "mach =" value = "100" /> <Eigenschaft name = "minidle" value = "10" /> <Eigenschaft name = "maxwait" value = "60000" /> <Eigenschaft name = "validationQuery" value = "select 'x'" /> <Eigenschaft name = "testonborrow" value = "false" /> <probanden name "testonraurn" value ". name = "testonReturn" value = "false" /> <Eigenschaft name = "test während value="1800" /> <property name="logAbandoned" value="true" /> <!-- Configure filters for monitoring statistics intercepts --> <property name="filters" value="config,mergeStat,wall,log4j2" /> <property name="connectionProperties" value="config.decrypt=true" /> </bean> <!-- serverB dataSource --> <bean id = "serverbdataSource" init-method = "init" destous-method = "close"> <Eigenschaft name = "url" value = "$ {db.serverb.master.url}" /> <Eigenschaft name = "userName" value = "$ {db.serverb.master.user}" /> <Stiefname = "Password". value = "$ {db.serverb.master.Password}" /> <Eigenschaft name = "TRAVERCLASSNAME" value = "$ {db.serverb.master.driver}" /> <Eigenschaftsname = "InitialSize" value = "5" /> <Eigenschaft name "maxactive" value = "100" /> <Stiefname = "machwait". value = "60000" /> <Eigenschaft name = "validationQuery" value = "select 'x'" /> <Eigenschaft name = "testonborrow" value = "false" /> <Eigenschaft name = "testonReturn" value = "false" /> <Eigenschaft name = "test während name = "mineVictableableIdletImemillis" value = "300000" /> <Eigenschaft name = "removeAbandoned" value = "true" /> <Eigenschaft name = "removeAbandonedTimeout" value = "1800" /> <Eigenschaft name = "logabonted" Value = "true" /> <!-Konfigurieren von Filtern für die Überwachung von Filtern für die Überwachung von Statistikabschnitt-> <immobilien name value = "config, mergestat, wand, log4j2" /> <Eigenschaft name = "ConnectionProperties" value = "config.decrypt = true" /> < /bean>Ich habe drei Datenquellen konfiguriert: opdataSource (die Datenquelle der Betriebsplattform selbst), ServeradataSource und ServerbDataSource.
2. Konfigurieren Sie MultiPledatasource
MultiPledatasource entspricht einem Proxy für die oben genannten drei Datenquellen. Wenn es wirklich mit Spring/MyBatis kombiniert wird, unterscheiden sich Multipledatasource und separat konfigurierte DataSource -Verwendung nicht:
<!-Spring Integration MyBatis: Konfigurieren Sie MultipledataSource-> <bean id = " <wert> classPath*:/sqlmapperXml/*/*. xml </value> </list> </property> <Eigenschaft name = "configLocation" value = "classPath: xml/mybatis-config.xml"> </Property> <Property = "typealiasespackage" com.xxxx.Platform.MoDell "/> <"/> global = "com.xxxx.platform.modell"/> <"," com.xxxx.platform.modell "/> <", "global ref="globalConfig" /> <property name="plugins"> <array> <!-- Pagination plugin configuration--> <bean id="paginationInterceptor" > <property name="dialectType" value="mysql" /> <property name="optimizeType" value="aliDruid" /> </bean> </array> </property> </bean> <!-- MyBatis Dynamische Implementierung-> <bean id = "mapperscannerConfigurer"> <!-Für die DAO-Schnittstelle dynamische Implementierung müssen Sie wissen, wo die Schnittstelle-> <Eigenschaft name = "Basepackage" value = "com.xxx.platform.mapper"/> <Eigenschaft name = "sqleSessionfactoryBeAnname" value = " <!-MP Global Configuration-> <bean id = "globalconfig"> <Eigenschaft name = "idType" value = "0" /> <Eigenschaft name = "dbcolumnderLine" value = "true" /> < /bean> <!-Transaction Management Configuration Konfigurationskonfiguration name = "dataSource". ref = "multiplydatasource"> </property> </bean>
Konzentrieren wir uns nach dem Verständnis des Standorts von MultipledataSource, wie Multiplidatasource implementiert werden kann. Die Konfigurationsdatei lautet wie folgt:
<bean id="multipleDataSource"> <property name="defaultTargetDataSource" ref="opDataSource" /> <property name="targetDataSources"> <map> <entry key="opDataSource" value-ref="opDataSource" /> <entry key="serverADataSource" value-ref="serverADataSource" /> <entry KEY = "ServerbDataSource" Value-ref = "serverbDataSource"/> </map> </property> </bean>
Der implementierte Java -Code lautet wie folgt, und es besteht keine zu viel Erklärung und es ist sehr klar auf einen Blick:
import org.springframework.jdbc.datasource.lookup.abstractroutingdataSource; AbstractroutingDataSource {private statische endgültige ThreadLocal <string> dataSourceKey = new inHeritablTheadLocal <string> (); public static void setDataSourceKey (String DataSource) {DataSourceKey.set (DataSource); } @Override Protected Object DeterminecurrentLookupkey () {return DataSourceKey.get (); } public static void RemedataSourceKey () {DataSourceKey.remove (); }}Aus dem AbstractroutingDataSource von Springerer geerbt, implementiert die abstrakte Methode DeterminencurrentLookupkey. Diese Methode ermittelt die Datenquellendatensource für diese Verbindung jedes Mal, wenn die Datenbankverbindung erhalten wird. Sie können sehen, dass der Federcode klar ist:
/*Anschluss erhalten*/ public Connection getConnection () löscht sqlexception {return DeterInetargetDataSource (). GetConnection (); } protected DataSource DeterInetargetDataSource () {assert.notnull (this.ResolvedDataSources, "DataSource -Router nicht initialisiert"); /*Der DeterminecurrentLookupkey hier ist eine abstrakte Schnittstelle, die den spezifischen Datenquellennamen erhalten*/ Object Lookupkey = DeterminecurrentLookupkey (); DataSource dataSource = (dataSource) this.ResolvedDataSources.get (Lookupkey); if ((dataSource == null) && (((this.Lenientfallback) || (Lookupkey == null)))) {dataSource = this.ResolvedDefaultDataSource; } if (dataSource == null) {neue illegaleStateException werfen ("" Zieldatenource kann nicht bestimmen, um Suchschlüssel [" + Lookupkey +"] "); } return DataSource; } /*Abstract Interface: Das heißt die Schnittstelle, die von unserem MultiPledataSource implementiert wurde* / geschütztes abstraktes Objektdeterminenzurrentlookupkey ();Schritt 2: Schalten Sie die Datenquelle jede Anforderung dynamisch um (Servicemethode) dynamisch.
Die Implementierungsidee besteht darin, die AOP -Idee von Spring zu verwenden, um jeden Service -Methode -Aufruf abzufangen und dann den Schlüssel der Daten in Multiplydatasource entsprechend dem Gesamtpfadnamen der Methode dynamisch zu wechseln. Unser Projekt für den Betrieb verschiedener Dienste, dh unterschiedliche Datenbanken, ist unabhängig voneinander. Es wird nicht empfohlen, verschiedene Datenquellen in derselben Servicemethode aufzurufen. Auf diese Weise müssen wir dynamisch bestimmen, ob die Frequenz des Schaltungsverbots auf der DAO -Ebene platziert werden muss, dh der SQL -Ebene. Darüber hinaus ist das Transaktionsmanagement nicht bequem.
Sehen wir uns die AOP -Implementierung dynamischer Schaltdatenquellen an:
importieren java.lang.reflect.proxy; import org.apache.commons.lang.classutils; import org.aspespep..lang.joInpoint; import org.aspespepj.lang.Annotation.aspep; * * @Author yuzhu.peng * @Since 2018-01-15 * / @Aspekt @Order (1) MultiplidataSourceInterceptor für öffentliche Klasse { /** * Der Interceptor achtet besondere Aufmerksamkeit auf das Umschalten von Datenquellen, bevor sie alle Geschäftsinimpusikklassen anfordern. Da mehrere Datenquellen verwendet werden, ist es am besten, Mapper nur in *serviceImpl aufzurufen. Andernfalls wird beim Aufrufen einer Tabelle, die keine Standarddatenquelle ist, eine Ausnahme, die in der Tabelle nicht vorhanden ist. joinpoint.gettarget (). getClass (); String className = clazz.getName (); if (clasutils.is -signible (clazz, proxy.class)) {className = joinpoint.getSignature (). getDeclaringTypeName (); } // Setzen Sie die Servera -Datenquelle mit dem Klassennamen. Andernfalls ist die Standardeinstellung die Datenquelle im Hintergrund if (className.contains (". Servera.")) {MultiPledataSource.setDataSourceKey (dbconstant.data_source_servera); } else if (className.contains (". serverb.")) {multipledataSource.setDataSourceKey (dbconstant.data_Source_Serverb); } else {multiPledataSource.setDataSourceKey (dbConstant.data_Source_OP); }} /*** Wenn der Vorgang abgeschlossen ist, tritt bei der häufigsten Klicken auf häufiges Klicken auf häufiges Klicken auf häufiges Datenquellenkonflikt ein Datenquellenkonflikt auf. Es handelt sich um eine Tabelle einer anderen Datenquelle, wird jedoch zu einer anderen Datenquelle ausgeführt. Der Bericht existiert nicht** @param Joinpoint* @throws Throwable*/ @after ("Ausführung (* com.xxxx.service ..*.* ServiceImpl.* (..)") public void removedatasoruce (joinpoint joinpoint) throwable {multiPledatasource.removedataSourceKey (); }}Schnitteln Sie alle ServiceImpl -Methoden, beurteilen Sie, welche Datenquellenfunktion zum vollständig qualifizierten Namen der Methode gehört, und wählen Sie dann die entsprechende Datenquelle aus. Lassen Sie nach Abschluss der Verteilung die aktuelle Datenquelle frei. Beachten Sie, dass ich Spring's @Order, Annotation, und ich werde als nächstes darüber sprechen. Bei der Definition mehrerer AOPS ist die Bestellung sehr nützlich.
andere:
Zu Beginn hat das Projekt keine Transaktionen eingeführt, also war alles in Ordnung. Sie können jedes Mal auf die richtige Datenquelle zugreifen. Nach dem Verbinden des Transaktionsmanagements von Spring können Sie die Datenquelle nicht dynamisch wechseln (es scheint, dass die Transaktion nicht effektiv ist, die beiden jedoch nicht gleichzeitig gültig sind). Später stellte ich fest, dass der Grund die Ausführungsreihenfolge von AOP war, also verwendete ich die oben erwähnte Federreihenfolge:
Je kleiner die Reihenfolge, die Ausführung ist zuerst. Zu diesem Zeitpunkt können Sie nicht nur die Datenquellen dynamisch wechseln, sondern auch erfolgreich Transaktionen (in derselben Datenquelle) verwenden.
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.