随着系統使用者通路量的不斷增加,資料庫的頻繁通路将成為我們系統的一大瓶頸之一。由于項目前期使用者量不大,我們實作單一的資料庫就能完成。但是後期單一的資料庫根本無法支撐龐大的項目去通路資料庫,那麼如何解決這個問題呢?
實際的應用中,資料庫都是讀多寫少(讀取資料的頻率高,更新資料的頻率相對較少),而讀取資料通常耗時比較長,占用資料庫伺服器的CPU較多,進而影響使用者體驗。我們通常的做法就是把查詢從主庫中抽取出來,采用多個從庫,使用負載均衡,減輕每個從庫的查詢壓力。
采用讀寫分離技術的目标:有效減輕Master庫的壓力,又可以把使用者查詢資料的請求分發到不同的Slave庫,進而保證系統的健壯性。我們看下采用讀寫分離的背景。
我們在項目開發初期的時候就設計了一個簡單的讀寫分離,現在我把demo分享給大家。
采用技術Spring + mybatis
首先定義一個annotation
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataSource {
public String value();
}
再定義一個HandleDataSource
public class HandleDataSource {
public static final ThreadLocal holder = new ThreadLocal();
public static void putDataSource(String datasource) {
holder.set(datasource);
public static String getDataSource() {
return holder.get();
定義一個切面
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
public class DataSourceAspect {
public void pointCut() {
};
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);
HandleDataSource.putDataSource(data.value());
} catch (Exception e) {
e.printStackTrace();
擷取資料源
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class ChooseDataSource extends AbstractRoutingDataSource {
protected Object determineCurrentLookupKey() {
return HandleDataSource.getDataSource();
配置XMl
classpath*:mysql.propertiescom.mysql.jdbc.Driver${jdbc.url}${jdbc.user}${jdbc.password}SELECT 1 FROM DUAL32510010000true60com.mysql.jdbc.Driver${jdbc.url.read}${jdbc.user.read}${jdbc.password.read}SELECT 1 FROM DUAL32510010000true60
注解到service接口上面
資料庫表就一張 根據mybatis的xml大家自己建一下
另外這裡還有一個瑕疵就是,當你使用注解事務的時候系統隻能讀取預設的資料源,這個問題主要是因為spring的事務和自定義的aop存在一個先後順序的問題
Spring中的事務是通過aop來實作的,當我們自己寫aop攔截的時候,會遇到跟spring的事務aop執行的先後順序問題,比如說動态切換資料源的問題,如果事務在前,資料源切換在後,會導緻資料源切換失效,是以就用到了Order(排序)這個關鍵字.
我們可以通過在@AspectJ的方法中實作org.springframework.core.Ordered 這個接口來定義order的順序,order 的值越小,說明越先被執行。
本文源碼擷取:關注我,感謝大家支援。點選
這裡加入擷取