Heim Java javaLernprogramm Beispiel dafür, wie Spring die Lese-/Schreibtrennung einer Datenbank implementiert

Beispiel dafür, wie Spring die Lese-/Schreibtrennung einer Datenbank implementiert

Jan 24, 2017 am 10:14 AM

Die meisten aktuellen großen E-Commerce-Systeme verwenden Lese-/Schreib-Trennungstechnologie auf Datenbankebene, bei der es sich um eine Master-Datenbank und mehrere Slave-Datenbanken handelt. Die Master-Bibliothek ist für die Datenaktualisierung und Echtzeit-Datenabfrage verantwortlich, und die Slave-Bibliothek ist natürlich für die Nicht-Echtzeit-Datenabfrage verantwortlich. Denn in tatsächlichen Anwendungen liest die Datenbank mehr und schreibt weniger (die Häufigkeit des Lesens von Daten ist hoch und die Häufigkeit der Aktualisierung von Daten relativ gering), und das Lesen von Daten dauert normalerweise lange und beansprucht viel CPU des Datenbankservers , also Auswirkungen auf die Benutzererfahrung. Unser üblicher Ansatz besteht darin, die Abfrage aus der Hauptdatenbank zu extrahieren, mehrere Slave-Datenbanken zu verwenden und den Lastausgleich zu verwenden, um den Abfragedruck auf jede Slave-Datenbank zu reduzieren.

Das Ziel der Verwendung der Lese-/Schreib-Trennungstechnologie besteht darin, den Druck auf die Master-Bibliothek effektiv zu reduzieren und Benutzeranfragen für Datenabfragen auf verschiedene Slave-Bibliotheken zu verteilen und so die Robustheit des Systems sicherzustellen. Schauen wir uns den Hintergrund der Einführung der Lese-/Schreibtrennung an.

Da das Geschäft der Website weiter wächst, die Datenmenge weiter zunimmt und es immer mehr Benutzer gibt, nimmt der Druck auf die Datenbank grundsätzlich zu Bei Bedarf kann die Strategie der Trennung von Lesen und Schreiben genutzt werden, um den Status quo zu ändern.

Wie können wir insbesondere in der Entwicklung leicht eine Trennung von Lesen und Schreiben erreichen? Derzeit werden zwei häufig verwendete Methoden verwendet:

1 Die erste Methode ist unsere am häufigsten verwendete Methode, nämlich das Definieren 2 Datenbankverbindung, eine ist MasterDataSource und die andere ist SlaveDataSource. Beim Aktualisieren von Daten lesen wir die MasterDataSource und beim Abfragen der Daten lesen wir die SlaveDataSource. Diese Methode ist sehr einfach, daher werde ich nicht auf Details eingehen.

2 Die zweite Methode des dynamischen Datenquellenwechsels besteht darin, die Datenquelle dynamisch in das Programm einzubinden, wenn das Programm ausgeführt wird, und dabei zu wählen, ob sie aus der Hauptbibliothek oder der Slave-Bibliothek liest. Die wichtigsten verwendeten Technologien sind: Annotation, Spring AOP, Reflection. Die Implementierungsmethode wird im Folgenden ausführlich vorgestellt.

Bevor wir die Implementierungsmethode vorstellen, bereiten wir zunächst einige notwendige Kenntnisse über die AbstractRoutingDataSource-Klasse vor.

Die AbstractRoutingDataSource-Klasse wurde nach Spring 2.0 hinzugefügt >

AbstractRoutingDataSource erbt AbstractDataSource, eine Unterklasse von DataSource. DataSource ist die Datenquellenschnittstelle von javax.sql, die wie folgt definiert ist:
public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {}
Nach dem Login kopieren

Die DataSource-Schnittstelle definiert zwei Methoden, die beide Datenbankverbindungen erhalten. Schauen wir uns an, wie AbstractRoutingDataSource die DataSource-Schnittstelle implementiert:
public interface DataSource extends CommonDataSource,Wrapper {
 
 /**
  * <p>Attempts to establish a connection with the data source that
  * this <code>DataSource</code> object represents.
  *
  * @return a connection to the data source
  * @exception SQLException if a database access error occurs
  */
 Connection getConnection() throws SQLException;
 
 /**
  * <p>Attempts to establish a connection with the data source that
  * this <code>DataSource</code> object represents.
  *
  * @param username the database user on whose behalf the connection is
  * being made
  * @param password the user&#39;s password
  * @return a connection to the data source
  * @exception SQLException if a database access error occurs
  * @since 1.4
  */
 Connection getConnection(String username, String password)
  throws SQLException;
 
}
Nach dem Login kopieren

public Connection getConnection() throws SQLException {
    return determineTargetDataSource().getConnection();
  }
 
  public Connection getConnection(String username, String password) throws SQLException {
    return determineTargetDataSource().getConnection(username, password);
  }
Nach dem Login kopieren

Offensichtlich ruft es seine eigene discoverTargetDataSource()-Methode auf, um die Verbindung zu erhalten. Die Methode „determinTargetDataSource“ ist wie folgt definiert:

protected DataSource determineTargetDataSource() {
    Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
    Object lookupKey = determineCurrentLookupKey();
    DataSource dataSource = this.resolvedDataSources.get(lookupKey);
    if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
      dataSource = this.resolvedDefaultDataSource;
    }
    if (dataSource == null) {
      throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
    }
    return dataSource;
  }
Nach dem Login kopieren

Was uns am meisten beschäftigt, sind die folgenden 2 Sätze:

Object lookupKey = determineCurrentLookupKey();
DataSource dataSource = this.resolvedDataSources.get(lookupKey);
Nach dem Login kopieren

Die Methode „defineCurrentLookupKey“ gibt den LookupKey zurück und die Methode „resolvedDataSources“ ruft die Datenquelle aus der Karte basierend auf dem LookupKey ab. „resolvedDataSources“ und „determinedCurrentLookupKey“ sind wie folgt definiert:

private Map<Object, DataSource> resolvedDataSources;
 
protected abstract Object determineCurrentLookupKey()
Nach dem Login kopieren

Haben wir angesichts der obigen Definition einige Ideen? „ResolvedDataSources“ ist ein Kartentyp und SlaveDataSource Speichern Sie es wie folgt in der Karte:

Beispiel dafür, wie Spring die Lese-/Schreibtrennung einer Datenbank implementiertWir schreiben eine Klasse DynamicDataSource, die AbstractRoutingDataSource erbt und deren Methode „defineCurrentLookupKey()“ implementiert, die den Kartenschlüssel zurückgibt, Master oder Sklave.

Okay, ich bin etwas müde, nachdem ich so viel geredet habe. Mal sehen, wie ich es umsetzen kann.

Die Technologie, die wir verwenden möchten, wurde oben erwähnt. Schauen wir uns zunächst die Definition von Annotation an:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataSource {
  String value();
}
Nach dem Login kopieren

Wir brauchen auch Um Spring zu implementieren, implementiert die abstrakte Klasse AbstractRoutingDataSource die Methode discoverCurrentLookupKey:

public class DynamicDataSource extends AbstractRoutingDataSource {
 
  @Override
  protected Object determineCurrentLookupKey() {
    // TODO Auto-generated method stub
    return DynamicDataSourceHolder.getDataSouce();
  }
 
}
 
 
public class DynamicDataSourceHolder {
  public static final ThreadLocal<String> holder = new ThreadLocal<String>();
 
  public static void putDataSource(String name) {
    holder.set(name);
  }
 
  public static String getDataSouce() {
    return holder.get();
  }
}
Nach dem Login kopieren

Aus der Definition von DynamicDataSource wird der DynamicDataSourceHolder.getDataSouce()-Wert zurückgegeben Die Methode DynamicDataSourceHolder.putDataSource() muss aufgerufen werden, wenn das Programm ausgeführt wird, um ihr einen Wert zuzuweisen. Das Folgende ist der Kernteil unserer Implementierung, der AOP-Teil, der wie folgt definiert ist:

public class DataSourceAspect {
 
  public void before(JoinPoint point)
  {
    Object target = point.getTarget();
    String method = point.getSignature().getName();
 
    Class<?>[] classz = target.getClass().getInterfaces();
 
    Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())
        .getMethod().getParameterTypes();
    try {
      Method m = classz[0].getMethod(method, parameterTypes);
      if (m != null && m.isAnnotationPresent(DataSource.class)) {
        DataSource data = m
            .getAnnotation(DataSource.class);
        DynamicDataSourceHolder.putDataSource(data.value());
        System.out.println(data.value());
      }
       
    } catch (Exception e) {
      // TODO: handle exception
    }
  }
}
Nach dem Login kopieren

Um das Testen zu erleichtern, habe ich Definiert 2 Datenbanken, Shop simuliert die Master-Bibliothek und Test simuliert die Slave-Bibliothek. Die Tabellenstruktur von Shop und Test ist gleich, aber die Daten sind unterschiedlich. Die Datenbankkonfiguration ist wie folgt:

<bean id="masterdataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://127.0.0.1:3306/shop" />
    <property name="username" value="root" />
    <property name="password" value="yangyanping0615" />
  </bean>
 
  <bean id="slavedataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://127.0.0.1:3306/test" />
    <property name="username" value="root" />
    <property name="password" value="yangyanping0615" />
  </bean>
   
    <beans:bean id="dataSource" class="com.air.shop.common.db.DynamicDataSource">
    <property name="targetDataSources">
       <map key-type="java.lang.String">
         <!-- write -->
         <entry key="master" value-ref="masterdataSource"/>
         <!-- read -->
         <entry key="slave" value-ref="slavedataSource"/>
       </map>
        
    </property>
    <property name="defaultTargetDataSource" ref="masterdataSource"/>
  </beans:bean>
 
  <bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
  </bean>
 
 
  <!-- 配置SqlSessionFactoryBean -->
  <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="configLocation" value="classpath:config/mybatis-config.xml" />
  </bean>
Nach dem Login kopieren

Konfiguration im Frühjahr AOP-Konfiguration hinzufügen

<!-- 配置数据库注解aop -->
  <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  <beans:bean id="manyDataSourceAspect" class="com.air.shop.proxy.DataSourceAspect" />
  <aop:config>
    <aop:aspect id="c" ref="manyDataSourceAspect">
      <aop:pointcut id="tx" expression="execution(* com.air.shop.mapper.*.*(..))"/>
      <aop:before pointcut-ref="tx" method="before"/>
    </aop:aspect>
  </aop:config>
  <!-- 配置数据库注解aop -->
Nach dem Login kopieren

Das Folgende ist die Definition von MyBatis's UserMapper Beim Testen liest die Anmeldung die Master-Bibliothek und die Benutzerliste liest die Slave-Bibliothek:

public interface UserMapper {
  @DataSource("master")
  public void add(User user);
 
  @DataSource("master")
  public void update(User user);
 
  @DataSource("master")
  public void delete(int id);
 
  @DataSource("slave")
  public User loadbyid(int id);
 
  @DataSource("master")
  public User loadbyname(String name);
   
  @DataSource("slave")
  public List<User> list();
} 
Nach dem Login kopieren

Okay, führen Sie unsere Eclipse aus, um den Effekt zu sehen, geben Sie ein Geben Sie den Benutzernamen admin ein und melden Sie sich an, um den Effekt zu sehen

Spring 实现数据库读写分离的示例

Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass er zum Lernen aller beiträgt. Ich hoffe auch, dass jeder die PHP-Chinesisch-Website unterstützt.

Weitere verwandte Artikel zu Beispielen für die Implementierung der Datenbank-Lese-Schreib-Trennung durch Spring finden Sie auf der chinesischen PHP-Website!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

AI Hentai Generator

AI Hentai Generator

Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

R.E.P.O. Energiekristalle erklärten und was sie tun (gelber Kristall)
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Beste grafische Einstellungen
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. So reparieren Sie Audio, wenn Sie niemanden hören können
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Wie man alles in Myrise freischaltet
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Wie funktioniert der Klassenladungsmechanismus von Java, einschließlich verschiedener Klassenloader und deren Delegationsmodelle? Wie funktioniert der Klassenladungsmechanismus von Java, einschließlich verschiedener Klassenloader und deren Delegationsmodelle? Mar 17, 2025 pm 05:35 PM

Mit der Klassenbelastung von Java wird das Laden, Verknüpfen und Initialisieren von Klassen mithilfe eines hierarchischen Systems mit Bootstrap-, Erweiterungs- und Anwendungsklassenloadern umfasst. Das übergeordnete Delegationsmodell stellt sicher

Wie implementiere ich mehrstufige Caching in Java-Anwendungen mit Bibliotheken wie Koffein oder Guava-Cache? Wie implementiere ich mehrstufige Caching in Java-Anwendungen mit Bibliotheken wie Koffein oder Guava-Cache? Mar 17, 2025 pm 05:44 PM

In dem Artikel wird in der Implementierung von mehrstufigem Caching in Java mithilfe von Koffein- und Guava-Cache zur Verbesserung der Anwendungsleistung erläutert. Es deckt die Einrichtungs-, Integrations- und Leistungsvorteile sowie die Bestrafung des Konfigurations- und Räumungsrichtlinienmanagements ab

Wie kann ich JPA (Java Persistence-API) für Objektrelationszuordnungen mit erweiterten Funktionen wie Caching und faulen Laden verwenden? Wie kann ich JPA (Java Persistence-API) für Objektrelationszuordnungen mit erweiterten Funktionen wie Caching und faulen Laden verwenden? Mar 17, 2025 pm 05:43 PM

In dem Artikel werden mit JPA für Objektrelationszuordnungen mit erweiterten Funktionen wie Caching und faulen Laden erläutert. Es deckt Setup, Entity -Mapping und Best Practices zur Optimierung der Leistung ab und hebt potenzielle Fallstricke hervor. [159 Charaktere]

Wie benutze ich Maven oder Gradle für das fortschrittliche Java -Projektmanagement, die Erstellung von Automatisierung und Abhängigkeitslösung? Wie benutze ich Maven oder Gradle für das fortschrittliche Java -Projektmanagement, die Erstellung von Automatisierung und Abhängigkeitslösung? Mar 17, 2025 pm 05:46 PM

In dem Artikel werden Maven und Gradle für Java -Projektmanagement, Aufbau von Automatisierung und Abhängigkeitslösung erörtert, die ihre Ansätze und Optimierungsstrategien vergleichen.

Wie erstelle und verwende ich benutzerdefinierte Java -Bibliotheken (JAR -Dateien) mit ordnungsgemäßem Versioning und Abhängigkeitsmanagement? Wie erstelle und verwende ich benutzerdefinierte Java -Bibliotheken (JAR -Dateien) mit ordnungsgemäßem Versioning und Abhängigkeitsmanagement? Mar 17, 2025 pm 05:45 PM

In dem Artikel werden benutzerdefinierte Java -Bibliotheken (JAR -Dateien) mit ordnungsgemäßem Versioning- und Abhängigkeitsmanagement erstellt und verwendet, wobei Tools wie Maven und Gradle verwendet werden.

See all articles