Heim  >  Artikel  >  Java  >  Wie Spring Boot die Lese-/Schreibtrennung der Datenbank implementiert

Wie Spring Boot die Lese-/Schreibtrennung der Datenbank implementiert

高洛峰
高洛峰Original
2018-05-18 11:14:292313Durchsuche

Hintergrund

Wie kann nach der Konfiguration der Master-Slave-Datenbank eine Lese-/Schreibtrennung auf Codeebene erreicht werden?

Benutzerdefiniertes Datenbankrouting

Spring Boot stellt AbstractRoutingDataSource bereit, um die aktuelle Datenbank gemäß benutzerdefinierten Regeln auszuwählen, sodass wir die lesende Slave-Bibliothek vor dem Ausführen der Abfrage und danach festlegen können Die Ausführung ist abgeschlossen. Anschließend wird die Hauptdatenbank wiederhergestellt.

Implementieren Sie eine dynamisch routbare Datenquelle und führen Sie

ReadWriteSplitRoutingDataSource.java vor jedem Datenbankabfragevorgang aus

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
 
/**
 * @author songrgg
 * @since 1.0
 */
public class ReadWriteSplitRoutingDataSource extends AbstractRoutingDataSource {
  @Override
  protected Object determineCurrentLookupKey() {
    return DbContextHolder.getDbType();
  }
}

Die private Thread-Routing-Konfiguration für ReadWriteSplitRoutingDataSource liest die Konfiguration dynamisch

DbContextHolder.java

/**
 * @author songrgg
 * @since 1.0
 */
public class DbContextHolder {
  public enum DbType {
    MASTER,
    SLAVE
  }
 
  private static final ThreadLocal<DbType> contextHolder = new ThreadLocal<>();
 
  public static void setDbType(DbType dbType) {
    if(dbType == null){
      throw new NullPointerException();
    }
    contextHolder.set(dbType);
  }
 
  public static DbType getDbType() {
    return contextHolder.get() == null ? DbType.MASTER : contextHolder.get();
  }
 
  public static void clearDbType() {
    contextHolder.remove();
  }
}

AOP-optimierter Code

Verwenden Sie AOP, um den Vorgang zum Festlegen der Datenbank aus dem Code zu extrahieren. Die Granularität wird hier gesteuert Verwenden Sie daher die Form von Annotationen, um die an dieser Methode beteiligten Datenbanktransaktionen als schreibgeschützt und aus der Datenbank zu markieren.

Schreibgeschützte Annotation, die zum Annotieren der Datenbankoperation der Methode nur aus der Slave-Datenbank verwendet wird.

ReadOnlyConnection.java

package com.wallstreetcn.hatano.config;
 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
/**
 * Indicates the database operations is bound to the slave database.
 * AOP interceptor will set the database to the slave with this interface.
 * @author songrgg
 * @since 1.0
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ReadOnlyConnection {
}

ReadOnlyConnectionInterceptor.java

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
 
/**
 * Intercept the database operations, bind database to read-only database as this annotation
 * is applied.
 * @author songrgg
 * @since 1.0
 */
@Aspect
@Component
public class ReadOnlyConnectionInterceptor implements Ordered {
 
  private static final Logger logger = LoggerFactory.getLogger(ReadOnlyConnectionInterceptor.class);
 
  @Around("@annotation(readOnlyConnection)")
  public Object proceed(ProceedingJoinPoint proceedingJoinPoint, ReadOnlyConnection readOnlyConnection) throws Throwable {
    try {
      logger.info("set database connection to read only");
      DbContextHolder.setDbType(DbContextHolder.DbType.SLAVE);
      Object result = proceedingJoinPoint.proceed();
      return result;
    } finally {
      DbContextHolder.clearDbType();
      logger.info("restore database connection");
    }
  }
 
  @Override
  public int getOrder() {
    return 0;
  }
}

UserService.java

@ReadOnlyConnection
public List<User> getUsers(Integer page, Integer limit) {
  return repository.findAll(new PageRequest(page, limit));
}

Druid-Datenbankverbindungspool konfigurieren

build.gradle

compile("com.alibaba:druid:1.0.18")

Groovy Dependency Injection

DataSource konfigurieren als Routbare Datenquelle

context.groovy

import com.alibaba.druid.pool.DruidDataSource
import DbContextHolder
import ReadWriteSplitRoutingDataSource
 
** SOME INITIALIZED CODE LOAD PROPERTIES **
def dataSourceMaster = new DruidDataSource()
dataSourceMaster.url = properties.get(&#39;datasource.master.url&#39;)
println("master set to " + dataSourceMaster.url)
dataSourceMaster.username = properties.get(&#39;datasource.master.username&#39;)
dataSourceMaster.password = properties.get(&#39;datasource.master.password&#39;)
 
def dataSourceSlave = new DruidDataSource()
dataSourceSlave.url = properties.get(&#39;datasource.slave.url&#39;)
println("slave set to " + dataSourceSlave.url)
dataSourceSlave.username = properties.get(&#39;datasource.slave.username&#39;)
dataSourceSlave.password = properties.get(&#39;datasource.slave.password&#39;)
beans {
  dataSource(ReadWriteSplitRoutingDataSource) { bean ->
    targetDataSources = [
        (DbContextHolder.DbType.MASTER): dataSourceMaster,
        (DbContextHolder.DbType.SLAVE): dataSourceSlave
    ]
  }
}

Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass er für das Lernen aller hilfreich ist, und ich hoffe, dass jeder ihn unterstützt die chinesische PHP-Website.

Weitere Artikel darüber, wie Spring Boot die Lese-/Schreibtrennung von Datenbanken implementiert, finden Sie auf der chinesischen PHP-Website!

Stellungnahme:
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