首頁  >  文章  >  Java  >  Spring boot實作資料庫讀寫分離的方法

Spring boot實作資料庫讀寫分離的方法

高洛峰
高洛峰原創
2018-05-18 11:14:292408瀏覽

背景

資料庫配置主從之後,如何在程式碼層面實現讀寫分離?

用戶自訂設定資料庫路由

Spring boot提供了AbstractRoutingDataSource根據使用者定義的規則選擇目前的資料庫,這樣我們可以在執行查詢之前,設定讀取從庫,執行完成後,還原到主庫。

實作可動態路由的資料來源,在每次資料庫查詢操作前執行

ReadWriteSplitRoutingDataSource.java

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

執行緒私有路由配置,用於ReadWriteSplitRoutingDatacc​​ridr.com程式碼

利用AOP將設定資料庫的操作從程式碼中抽離,這裡的粒度控制在方法級別,所以利用註解的形式標註這個方法涉及的資料庫事務只讀,走從庫。

只讀註解,用於標註方法的資料庫操作只走從函式庫。

ReadOnlyConnection.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();
  }
}

ReadOnlyConnectionInterceptor.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 {
}

UserService.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;
  }
}

設定Druid資料庫連線)

groovy依賴注入

設定dataSource為可路由資料來源

context.groovy

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

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援PHP中文網。

更多Spring boot實作資料庫讀寫分離的方法相關文章請關注PHP中文網!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn