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('datasource.master.url') println("master set to " + dataSourceMaster.url) dataSourceMaster.username = properties.get('datasource.master.username') dataSourceMaster.password = properties.get('datasource.master.password') def dataSourceSlave = new DruidDataSource() dataSourceSlave.url = properties.get('datasource.slave.url') println("slave set to " + dataSourceSlave.url) dataSourceSlave.username = properties.get('datasource.slave.username') dataSourceSlave.password = properties.get('datasource.slave.password') 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!