spring結合mybatis實現數據庫讀寫分離


隨着系統用戶訪問量的不斷增加,數據庫的頻繁訪問將成為我們系統的一大瓶頸之一。由於項目前期用戶量不大,我們實現單一的數據庫就能完成。但是后期單一的數據庫根本無法支撐龐大的項目去訪問數據庫,那么如何解決這個問題呢?



實際的應用中,數據庫都是讀多寫少(讀取數據的頻率高,更新數據的頻率相對較少),而讀取數據通常耗時比較長,占用數據庫服務器的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接口上面


源碼地址

http://ccblog.oss-cn-hangzhou.aliyuncs.com/file/dbShard_demo.rar


數據庫表就一張 根據mybatis的xml大家自己建一下




另外這里還有一個瑕疵就是,當你使用注解事務的時候系統只能讀取默認的數據源,這個問題主要是因為spring的事務和自定義的aop存在一個先后順序的問題



 Spring中的事務是通過aop來實現的,當我們自己寫aop攔截的時候,會遇到跟spring的事務aop執行的先后順序問題,比如說動態切換數據源的問題,如果事務在前,數據源切換在后,會導致數據源切換失效,所以就用到了Order(排序)這個關鍵字.

        我們可以通過在@AspectJ的方法中實現org.springframework.core.Ordered 這個接口來定義order的順序,order 的值越小,說明越先被執行。








免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM